The connection is up, the handshake completes, small requests get answered — but the moment real data is supposed to flow, everything stalls. This symptom almost always points to the same cause, and it has nothing to do with routing or firewall rules.
Two terms, two layers
The MTU (Maximum Transmission Unit) is the largest IP packet a link can carry in one piece. On Ethernet that is 1500 bytes. It is a property of the path, not of the connection.
The MSS (Maximum Segment Size) is the largest payload of a TCP segment. It is a property of the connection: during the handshake both ends announce in their SYN how much they are prepared to accept.
The two are linked by the headers that still have to fit:
MSS = MTU − IP header − TCP header
IPv4: 1500 − 20 − 20 = 1460
IPv6: 1500 − 40 − 20 = 1440
A host on Ethernet therefore usually announces an MSS of 1460. That is the number you see in every SYN packet — and the starting point for everything that follows.
Where the MTU shrinks
As long as the entire path handles 1500 bytes, none of this ever comes up. It gets interesting the moment something encapsulates — every additional wrapper costs room:
- PPPoE — 8 bytes, MTU 1492, giving an MSS of 1452
- GRE — 24 bytes, MTU 1476, giving an MSS of 1436
- IPsec — roughly 50 to 70 bytes depending on mode and ciphers; in practice you often end up around 1400
With IPsec it pays to measure rather than calculate: the exact overhead depends on transport or tunnel mode, the encryption and authentication algorithms, and whether NAT traversal adds another layer.
Why nobody notices — until it is too late
There is a mechanism for exactly this. With path MTU discovery the sender sets the DF bit in the IP header: do not fragment. When a router hits a link that cannot pass the packet in one piece, it drops the packet and sends back an ICMP message — type 3, code 4, “fragmentation needed and DF set”. That message carries the size that would fit, and the sender reduces its segments accordingly.
This only works as long as that ICMP packet actually arrives. If it gets dropped along the way — because someone considers ICMP inherently unsafe and blocks all of it — the sender never learns that its packets are too big. It keeps sending them, they keep disappearing, and nobody reports it. This is known as a PMTUD black hole.
The symptoms are distinctive:
- The TCP handshake works — those packets are tiny
- Small requests get answered
- Larger transfers stall midway and eventually time out
- SSH login succeeds, but
lsin a large directory hangs - A web page loads forever while ping looks perfectly healthy
It is precisely this mixture that sends troubleshooting down the wrong path: reachability is fine, routing is correct, the firewall rule matches — and still nothing gets through.
Proving it
The quickest test is a ping of fixed size with the DF bit set. You deliberately send a packet that fills the presumed MTU exactly and see whether it survives:
Windows: ping -f -l 1472 target.example
Linux: ping -M do -s 1472 target.example
The 1472 is not arbitrary: 1472 bytes of payload plus an 8-byte ICMP header plus a 20-byte IP header add up to exactly 1500. If no reply comes back, reduce the value step by step. The first size that gets through, plus 28, is the actual MTU of the path.
If you want to be precise, look at the SYN in a packet capture. The announced MSS sits right there as a TCP option — and immediately tells you whether something along the path has already adjusted it.
The fix: MSS clamping
You could adjust the MTU on every endpoint. In a corporate network that is hopeless. The practical route runs through the router at the tunnel: it actively rewrites the MSS value in every SYN passing through before forwarding it. Both ends then agree on a size that fits from the very beginning — no ICMP required.
Cisco IOS, on the tunnel interface:
ip tcp adjust-mss 1360
FortiGate, in the firewall policy:
set tcp-mss-sender 1350
set tcp-mss-receiver 1350
The exact value follows the real MTU of the tunnel. A deliberately conservative number costs a little throughput, but considerably less grief than a black hole that only shows up under load.
One important limitation: MSS clamping only affects TCP, because that is the only place where a segment size is negotiated. UDP-based protocols — QUIC, and with it a growing share of web traffic, DNS with large responses, VPN over UDP — are untouched by it. There, only a correctly configured path MTU or fragmentation helps.
What to remember
When a connection comes up but nothing large fits through, the MTU is the first suspect — ahead of routing and rule sets. Two minutes with a fixed-size ping often save half a day of looking in the wrong place.
And if you block ICMP across the board, at least let type 3 code 4 through. Otherwise you are disabling the very mechanism that would solve this problem on its own.