MTU & MSS Mismatches — 'Works in the Office, Broken Over VPN'
The Symptom Pattern That Points Directly at MTU
- "Website loads the homepage but hangs on login — the POST never completes"
- "Large file downloads fail at exactly the same point every time"
- "SSH connects and I can authenticate, but the terminal freezes when I paste more than a few lines"
- "Works fine on the office network, broken as soon as users connect to VPN"
- "HTTPS to internal servers works, HTTPS to external sites hangs"
Why MTU Problems Are Invisible to Ping
The MTU and MSS Relationship — What Actually Breaks
Maximum Transmission Unit is the largest frame a physical link can carry. Maximum Segment Size is the TCP-layer value that limits how large a single TCP data segment can be. They are related but set independently, and the mismatch between them is where production failures hide.
| Layer | Value | Where It Is Set | What Breaks When Wrong |
|---|---|---|---|
| Layer 2 (Ethernet) | MTU: 1500 bytes | Network interface configuration, switch port | Fragmentation required — or if DF bit set, packets silently dropped |
| Layer 3 (IP) | DF bit (Don't Fragment) | Set by TCP stack or application | ICMP 'fragmentation needed' must be returned — blocked firewalls cause PMTUD to fail |
| Layer 4 (TCP) | MSS: typically 1460 bytes (1500 - 20 IP - 20 TCP) | Negotiated in SYN/SYN-ACK handshake | If MSS is too high for the path, large segments get dropped silently |
| VPN Tunnel | Overhead: 50-100 bytes depending on protocol | VPN configuration | Effective MTU drops — packets that fit the Ethernet link no longer fit the tunnel |
Why VPN Makes This Worse
A VPN tunnel adds overhead — IPsec ESP headers, GRE encapsulation, or TLS wrapping depending on the VPN type. A packet that is exactly 1500 bytes on the LAN side will be 1548-1600 bytes after VPN encapsulation. That packet no longer fits the 1500-byte MTU of the internet link — and if the original IP header had the DF bit set, the packet gets dropped with no notification reaching the application.
Path MTU Discovery depends on ICMP Type 3 Code 4 — "Fragmentation Needed" — being delivered back to the sender. Most enterprise firewalls and many ISP devices block ICMP. When ICMP is blocked, PMTUD silently fails and large packets are dropped forever. The connection never recovers.
The Debug Sequence — Confirming MTU Is the Cause
Step 1: The Definitive Test
! The single most important test for MTU diagnosis: ! Send a large packet with DF bit set — if this fails but small ping succeeds, MTU is the problem ! From a Windows client: ping <destination-ip> -f -l 1472 ! -f = set Don't Fragment bit ! -l 1472 = 1472 bytes payload + 28 bytes IP/ICMP header = 1500 total ! If this succeeds: MTU is fine on this path ! If this fails: MTU problem confirmed ! Try smaller sizes to find the exact MTU ceiling: ping <destination-ip> -f -l 1400 ping <destination-ip> -f -l 1300 ping <destination-ip> -f -l 1200 ! The largest size that succeeds tells you the effective MTU ! From a Linux/macOS client: ping -M do -s 1472 <destination-ip> ! -M do = set DF bit ! -s 1472 = payload size ! From Cisco IOS router: ping <destination-ip> size 1500 df-bit repeat 5 ! This is the router-originated version — tests the path from the router itself
Step 2: Check Interface MTU Configuration
! Check current MTU on all interfaces show interfaces | include MTU|line protocol ! Check specific interface show interface GigabitEthernet0/0 | include MTU ! Check MTU on subinterfaces (common mismatch point) show interfaces | include Ethernet|MTU ! For tunnel interfaces — where the mismatch usually lives: show interface Tunnel0 ! Look for: MTU 1476 bytes (or whatever value is set) ! Compare this to physical interface MTU of 1500 ! The tunnel MTU should be physical MTU minus tunnel overhead
Step 3: Trace Where Packets Are Being Dropped
! Check if ICMP unreachable messages are being generated ! (confirms fragmentation is happening or DF-drop is happening) show ip interface | include Unreachables ! Debug IP ICMP to see fragmentation-needed messages: debug ip icmp ! WARNING: Use on low-traffic interfaces only — very verbose ! Look for: "ICMP: dst (x.x.x.x) frag. needed and DF set, sending" ! This confirms the router is generating PMTUD responses ! Check if ICMP unreachables are disabled (blocks PMTUD response) show running-config | include no ip unreachables ! If you see "no ip unreachables" on the interface — this blocks PMTUD ! Re-enable with: ip unreachables (on the outbound interface) ! Check MTU on the path end-to-end using traceroute with probe size traceroute <destination> size 1500 df-bit
Step 4: Check MSS in TCP Sessions
! On Cisco router — check tcp adjust-mss configuration show running-config | include tcp adjust-mss ! Check active TCP sessions MSS negotiation: ! Capture packets and look at SYN and SYN-ACK for MSS option ! In Wireshark: tcp.flags.syn==1 → look at TCP Options → MSS value ! On PAN-OS — check MSS clamping in interface config show interface ethernet1/1 ! Look for: "MSS Adjustment" in the output ! On Linux — check interface MTU ip link show ! Look for: mtu 1500 or whatever the value is ! Check effective MSS for a connection: ss -ti dst <remote-ip> ! Shows: rcvmss, advmss, pmtu values
Root Cause Patterns and Fixes
| Root Cause | Where to Find It | Fix |
|---|---|---|
| VPN tunnel overhead not accounted for | Tunnel interface MTU > physical MTU minus overhead | Set tunnel interface MTU to 1400-1420 for IPsec, 1476 for GRE |
| ICMP unreachables disabled — PMTUD broken | show running | include no ip unreachables on WAN interface | ip unreachables on the WAN-facing interface, AND allow ICMP type 3 through firewall |
| MSS not clamped on tunnel or WAN interface | TCP sessions negotiating MSS of 1460 but path cannot carry it | ip tcp adjust-mss 1452 on the WAN or tunnel interface (both directions) |
| Jumbo frames misconfiguration | Some switches set to 9000 MTU, others at 1500 — inconsistent across path | Standardize MTU across all devices in the path, or explicitly set DF-bit handling |
| Docker/container networking | Container veth interfaces with lower MTU than host | Set MTU in docker daemon.json to match the host path MTU |
The MSS Clamp — Preferred Fix for Most Environments
! Apply MSS clamping on the interface where packets exit to the problem path ! This modifies the MSS value in TCP SYN packets to prevent oversized segments ! On Cisco IOS — apply to the WAN or tunnel interface: interface GigabitEthernet0/0 ip tcp adjust-mss 1452 ! This tells the router to rewrite any TCP MSS value above 1452 to 1452 ! 1452 = 1500 (Ethernet) - 20 (IP) - 20 (TCP) - 8 (overhead buffer) ! For IPsec VPN tunnels — use a lower value: interface Tunnel0 ip tcp adjust-mss 1360 ! IPsec ESP overhead: ~50-60 bytes ! 1500 - 60 (IPsec) - 20 (IP) - 20 (TCP) = approximately 1360-1400 ! Verify the clamping is working: ! Run a packet capture on the tunnel interface ! Check SYN packets outbound — MSS should now show 1452 (or your set value) ! NOT the original 1460 that the client negotiated ! On PAN-OS — MSS adjustment in Network > Interfaces > Advanced tab ! Or via CLI: set network interface ethernet ethernet1/1 adjust-tcp-mss enable yes set network interface ethernet ethernet1/1 adjust-tcp-mss ipv4-mss-adjustment 40
Why 1452 and Not 1460
The VPN-Specific Scenario — Full Debug Flow
The most common MTU complaint: everything works on the corporate LAN, everything breaks when connected to VPN. Here is the exact sequence that finds the cause every time.
! Step 1: Confirm the path works without VPN ! From client machine ON the LAN (not VPN): ping <problem-destination> -f -l 1472 ! Must succeed — establishes baseline ! Step 2: Connect to VPN, repeat the same test ping <problem-destination> -f -l 1472 ! If this fails: MTU problem is in the VPN path ! Step 3: Find the working MTU over VPN ping <problem-destination> -f -l 1300 ping <problem-destination> -f -l 1350 ping <problem-destination> -f -l 1400 ! Find the largest size that succeeds ! Step 4: Calculate the overhead ! If 1400 succeeds but 1450 fails: ! Effective MTU = 1400 + 28 (ICMP overhead) = 1428 ! Tunnel overhead = 1500 - 1428 = 72 bytes ! That is consistent with IPsec ESP in tunnel mode ! Step 5: Fix — apply MSS clamping on the VPN gateway interface ! The VPN gateway router or firewall: interface Tunnel0 ip tcp adjust-mss 1360 ! This prevents TCP from negotiating segments too large for the tunnel ! Step 6: Verify fix ! Run a file download or HTTPS session that was previously failing ! If it now completes — MTU was the cause
The reason "restart fixed it" sometimes works for MTU issues: a TCP connection that gets stuck negotiating with the original (too-large) MSS will stay stuck. After restart, if PMTUD has figured out the correct path MTU (or if the MSS clamp is now in place), new connections negotiate the correct MSS from the start. The connection was not fixed — it was replaced with a new connection that does not have the problem.