The Symptom: “It Works Sometimes”
Large file transfers work fine locally but timeout over VPN. Video calls drop during screen shares. Database backups fail randomly. You restart things and sometimes they work. You run the same command twice and the second time fails.
Classic MTU problem. Nobody thinks to check it because you inherited the network and it’s been like that for years.
What Is MTU Anyway?
MTU = Maximum Transmission Unit. It’s the largest frame your network can send in one packet. Standard Ethernet is 1500 bytes. Jumbo frames go to 9000. Your VPN might use 1280. Tunnel protocols (WireGuard, OpenVPN) add overhead.
When you send data bigger than the MTU, one of two things happens:
- The system fragments it (breaks it into smaller pieces) and reassembles it—slow but works
- The
DFbit (Don’t Fragment) is set and the packet is dropped—silent failure, retry, timeout
Most VPNs set the DF bit. Most tunnels don’t advertise their actual MTU properly. Result: transfers work for small files, hang forever on large ones.
The Diagnosis: Path MTU Discovery
Find the actual MTU being used on a path:
# Linux: Use tracepathtracepath -m 15 example.com 22
# Output shows where MTU drops:# hop 1: [reached, mtu 1500]# hop 2: [reached, mtu 1500]# hop 3: [reached, mtu 1350] <-- MTU drops here# hop 4: no replyOr use ping with DF bit set:
# Find the largest packet that doesn't fragment:ping -M do -s 1472 example.com
# 1472 = 1500 (MTU) - 28 (IP/ICMP headers)# If this fails, try smaller:ping -M do -s 1400 example.comping -M do -s 1300 example.comping -M do -s 1200 example.comWhen it succeeds, you’ve found your path MTU. Most home networks max out around 1500. VPNs often drop to 1280 or less.
Check Your Local Interface MTU
ip link showYou’ll see something like:
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 655362: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 15003: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 15004: tun0: <POINTOPOINT,MULTICAST,UP,LOWER_UP> mtu 1280Notice tun0 (VPN interface) has MTU 1280 while eth0 has 1500. When you’re on the VPN sending traffic, your effective MTU is 1280.
The Real Problem: Encapsulation Overhead
Your VPN or tunnel adds protocol overhead. Here’s what actually happens:
- Ethernet frame: max 1500 bytes
- IP header: 20 bytes
- VPN encryption overhead: varies (OpenVPN +20-40, WireGuard +40, IPSec varies)
- Your actual payload: 1500 - overhead
If you’re trying to send a 1500-byte packet through a tunnel with 40 bytes overhead, the tunnel has to fragment it. Fragments are slow and unreliable.
Solutions:
- Lower the MTU on the tunnel interface (quick fix):
sudo ip link set dev tun0 mtu 1420This tells the system to never send packets larger than 1420 through the VPN. No fragmentation, no drops.
- Configure the VPN to advertise correct MTU (proper fix):
For OpenVPN in /etc/openvpn/client.conf:
mtu-testfragment 1300For WireGuard in /etc/wireguard/wg0.conf:
[Interface]Address = 10.0.0.2/32MTU = 1420Test the Fix
Before and after:
# Before fix: large file stallsscp largefile.tar.gz user@remotehost:/tmp/
# After fix: completes instantlyscp largefile.tar.gz user@remotehost:/tmp/Or use iperf for network performance testing:
# On receiver:iperf -s
# On sender (check throughput):iperf -c receiver.host
# With incorrect MTU, you'll see low throughput and packet loss.# After fix, throughput jumps 5-10x.Real-World Debugging
# 1. Check if you can ping yourself over the tunnel:ping -M do -s 1472 10.0.0.1 # Your tunnel IP
# 2. If it fails, binary search for working size:ping -M do -s 1400 10.0.0.1ping -M do -s 1350 10.0.0.1ping -M do -s 1300 10.0.0.1 # <-- maybe works
# 3. That's your path MTU. Lower your interface MTU to leave headroom:sudo ip link set dev tun0 mtu 1280
# 4. Test again:ping -M do -s 1252 10.0.0.1 # 1280 - 28 byte headers
# 5. Try the large transfer againscp largefile user@remote:/tmp/The Permanent Fix
Edit /etc/systemd/network/tun0.network (or wherever your tunnel is defined):
[Match]Name=tun0
[Link]MTUBytes=1420Reboot (or systemctl restart systemd-networkd) and it sticks.
Why This Stays Broken
Most people don’t think about MTU until transfers fail. By then they’re tired and just restart the VPN or the server. MTU issues are invisible when you’re using small files.
But the moment someone tries to transfer a database dump or a VM backup, the tunnel becomes a bottleneck and nobody traces it back to frame size.
Check your MTU once. Fix it once. Never debug this problem again.