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,
lsof 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
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.