MTU (Maximum Transmission Unit) is the largest packet size an interface or path can carry without fragmentation. The standard Ethernet MTU is 1500 bytes. Most of the time you never think about it, until a VPN, tunnel or unusual network shrinks the usable size. Then you get some of the strangest symptoms in networking: SSH connects but freezes, websites half-load, large downloads stall while ping works fine.

MTU vs MSS

  • MTU is the maximum IP packet size (headers included) on a link. It’s 1500 on typical Ethernet.
  • MSS (Maximum Segment Size) is the maximum TCP payload: MTU minus the IP and TCP headers (40 bytes for IPv4, 60 for IPv6). So an MSS of 1460 fits a 1500 MTU.

TCP peers announce their MSS during the handshake, so TCP usually adapts. Problems arise when something in between has a smaller MTU, and the signal that should tell the sender (“fragmentation needed”, ICMP) gets lost.

Why tunnels reduce the MTU

Encapsulation adds headers:

Tunnel Typical overhead Common inner MTU
WireGuard 60 (IPv4 outer) / 80 (IPv6 outer) 1420 (default)
OpenVPN (UDP) ~50–70+ ~1400–1450
IPsec (ESP) ~50–80 ~1400–1438
GRE 24 1476
VXLAN 50 1450
PPPoE (home DSL/fibre) 8 1492

A 1500-byte packet entering a tunnel no longer fits in a 1500-byte outer packet.

Path MTU discovery and the “black hole”

Normally, a router that can’t forward a too-large packet (marked “don’t fragment”) sends back an ICMP “fragmentation needed” message (IPv6: “packet too big”). The sender then lowers its packet size. This is Path MTU Discovery (PMTUD).

If a firewall blocks those ICMP messages, the sender never learns. Large packets just disappear. That’s a PMTU black hole:

  • small packets work: ping, the TCP handshake, short responses, typing in SSH;
  • large packets vanish: full web pages, file transfers, ls of a big directory over SSH, TLS handshakes with large certificates.

That’s the classic MTU signature: connections establish, then hang when real data flows.

Don’t block ICMP entirely in your firewalls. At least allow “destination unreachable / fragmentation needed” (IPv4 type 3 code 4) and IPv6 “packet too big” (type 2). UFW’s default rules allow them.

Find the path MTU

Send pings with “don’t fragment” set and growing sizes. On Linux, -s is the payload, so add 28 bytes for the IPv4 and ICMP headers:

ping -M do -s 1472 -c 3 example.com     # 1472 + 28 = 1500
ping -M do -s 1400 -c 3 example.com

“Message too long” or no reply means the path MTU is smaller. Narrow it down until pings pass. tracepath does this automatically:

tracepath example.com
#  1?: [LOCALHOST]  pmtu 1500
#  …   pmtu 1420

Windows: ping -f -l 1472 example.com.

Fixing MTU problems

Set the interface MTU (tunnels, VPNs)

WireGuard (/etc/wireguard/wg0.conf):

[Interface]
MTU = 1420        # lower to 1380 or 1280 if clients sit behind PPPoE or other tunnels

Temporarily, for any interface:

ip link show eth0 | grep mtu
sudo ip link set dev wg0 mtu 1380

Permanently, on Ubuntu with netplan:

network:
  ethernets:
    eth0:
      mtu: 1500

See netplan and WireGuard.

MSS clamping (routers and VPN gateways)

On a Linux box that forwards traffic (a VPN server, NAT gateway), clamp the TCP MSS of forwarded connections to the path MTU. This fixes black holes for all clients, without touching them:

sudo iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu

nftables:

table inet mangle {
  chain forward { type filter hook forward priority mangle;
    tcp flags syn tcp option maxseg size set rt mtu }
}

Enable PMTU probing as a fallback

sudo sysctl -w net.ipv4.tcp_mtu_probing=1

This lets TCP detect black holes and lower its segment size itself. Make it persistent in /etc/sysctl.d/. See sysctl tuning.

Jumbo frames

Inside some data centres and private networks, MTU 9000 (“jumbo frames”) reduces overhead for heavy storage or replication traffic. It only works if every device on that segment supports it. Public internet traffic always uses 1500 or less. On a VPS, keep the provider’s default MTU on the public interface.

Quick reference

Task Command
Show MTU ip link show
Set MTU (temporary) ip link set dev IFACE mtu 1400
Test path MTU ping -M do -s 1472 host / tracepath host
Clamp MSS on a gateway iptables … -j TCPMSS --clamp-mss-to-pmtu
TCP probing net.ipv4.tcp_mtu_probing=1
WireGuard MTU = 1420 (lower if needed)

Related: tcpdump and ping and mtr.

  • Networking
  • Linux
  • VPN