MTU and Packet Fragmentation Explained
Learn what MTU is, how path MTU discovery works, why it breaks, and how to diagnose and fix MTU mismatches on Linux with practical commands and examples.
Before you start
- ▸Root or sudo access on the system being configured
- ▸Basic familiarity with network interface names (eth0, ens3, wg0, etc.)
- ▸iproute2 installed (provides ip, tracepath — present by default on all major distros)
MTU — Maximum Transmission Unit — is one of those networking fundamentals that hides quietly until it breaks things spectacularly. A misconfigured or mismatched MTU causes partial connectivity: pings work, but SSH sessions hang after the banner, web pages load halfway, or VPN tunnels drop large transfers silently. Understanding how MTU works and how to diagnose it saves enormous amounts of troubleshooting time.
What MTU Actually Is
MTU is the largest Layer 3 packet (IP datagram) that a network interface will transmit without fragmenting it. Ethernet's standard MTU is 1500 bytes. That number has been the default since the original Ethernet specification and is baked into virtually every network device today.
The MTU is not the same as the frame size. An Ethernet frame adds 14–18 bytes of Layer 2 header on top of the IP packet, so a 1500-byte MTU produces frames up to 1518 bytes on the wire. Some hardware supports jumbo frames, which push the MTU to 9000 bytes or higher — useful inside data centres but irrelevant and potentially harmful across the public internet.
When a packet is larger than the MTU of a link it must cross, one of two things happens:
- The router fragments the packet into smaller pieces (IPv4 only, and only if the DF bit is not set).
- The packet is dropped and an ICMP "Fragmentation Needed" message is sent back to the source (IPv4 with DF set, or any IPv6 traffic — IPv6 never fragments in transit).
Path MTU Discovery
Path MTU Discovery (PMTUD) is the mechanism by which a host automatically finds the smallest MTU across every hop between itself and a destination. The kernel sets the DF (Don't Fragment) bit on outgoing TCP packets and watches for ICMP Type 3 Code 4 ("Fragmentation Needed") messages. When one arrives, the kernel reduces the effective MTU for that path and retransmits.
PMTUD works well in theory but fails in practice when overzealous firewalls block all ICMP traffic. This produces the classic "black hole" symptom: small packets get through (ping, DNS), but anything requiring large packets (HTTPS, SSH data transfer, file copies) stalls or breaks.
Checking the Current MTU
On any modern Linux system, use ip (from iproute2) rather than the deprecated ifconfig:
ip link show
Look for the mtu field in the output next to each interface. To see a single interface:
ip link show dev eth0
Output will include something like mtu 1500 — your current configured MTU.
Testing for MTU Black Holes Manually
Send ICMP packets of decreasing sizes with DF set. The -M do flag sets DF; -s sets the payload size. Remember the kernel adds 28 bytes of IP+ICMP header, so -s 1472 produces a 1500-byte packet:
ping -M do -s 1472 -c 3 8.8.8.8
If that fails, step down until you find the largest size that succeeds:
ping -M do -s 1400 -c 3 8.8.8.8
ping -M do -s 1300 -c 3 8.8.8.8
The largest payload that gets a reply, plus 28, is the effective path MTU to that host.
Changing the MTU
Temporary Change (Survives Until Reboot)
sudo ip link set dev eth0 mtu 1400
Persistent Change — Debian/Ubuntu (systemd-networkd or NetworkManager)
If you use NetworkManager (desktop or server install), edit the connection:
nmcli connection show
nmcli connection modify "Wired connection 1" 802-3-ethernet.mtu 1400
nmcli connection up "Wired connection 1"
With systemd-networkd, create or edit /etc/systemd/network/10-eth0.network:
[Match]
Name=eth0
[Link]
MTUBytes=1400
[Network]
DHCP=yes
Then reload:
sudo systemctl restart systemd-networkd
Persistent Change — Fedora/RHEL/Rocky
NetworkManager is standard on these distros. Use nmcli as shown above, or edit the keyfile directly in /etc/NetworkManager/system-connections/. Look for an [ethernet] section and add mtu=1400.
Persistent Change — Arch Linux
Arch typically uses either systemd-networkd or NetworkManager. Use the relevant method above. If you use a manual netctl profile, add ExecUpPost='ip link set dev eth0 mtu 1400' to the profile.
MTU and VPNs: Where It Gets Messy
VPN tunnels (WireGuard, OpenVPN, IPsec) encapsulate packets inside other packets, consuming extra bytes for their own headers. This overhead means the tunnel's effective MTU must be lower than the physical interface's MTU to avoid fragmentation.
- WireGuard adds 60 bytes of overhead (IPv4) or 80 bytes (IPv6). With a 1500-byte physical MTU, set WireGuard's MTU to 1420.
- OpenVPN (UDP): A common safe value is 1400; tune with
--mssfixand--fragment. - PPPoE (common on DSL): Adds 8 bytes of overhead, reducing usable MTU to 1492. This is a very frequent source of MTU problems on home connections.
For WireGuard, set MTU in the interface config:
[Interface]
Address = 10.0.0.1/24
PrivateKey = ...
MTU = 1420
TCP MSS Clamping: The Firewall Fix
When you can't control both endpoints (e.g., a router you don't own is stripping ICMP), TCP MSS (Maximum Segment Size) clamping is the standard workaround. It rewrites the MSS value in TCP SYN packets passing through your firewall/router so that the TCP session never tries to use a segment size that would exceed the path MTU.
With nftables on a Linux router or VPN gateway:
sudo nft add table inet filter
sudo nft add chain inet filter FORWARD { type filter hook forward priority 0 \; }
sudo nft add rule inet filter FORWARD tcp flags syn tcp option maxseg size set rt mtu
rt mtu tells nftables to use the route's known MTU — this is cleaner than hardcoding a value. To make this persistent, add it to your /etc/nftables.conf.
With firewalld (Fedora/RHEL), direct rules are the practical path for MSS clamping since firewalld does not expose this as a first-class object. Add a direct rule or use a custom nftables passthrough policy alongside firewalld.
Verifying the Fix
After any MTU change, confirm the interface reports the new value:
ip link show dev eth0
Rerun the ping probe to confirm large packets now pass:
ping -M do -s 1372 -c 5 8.8.8.8
For a TCP-level check, use tracepath which discovers path MTU end-to-end:
tracepath 8.8.8.8
The last column of output shows the MTU detected at each hop. A sudden drop in the MTU column points to the hop where the bottleneck sits.
Troubleshooting
SSH Connects but Hangs After Login
Classic MTU black hole. The SSH banner (small) gets through; subsequent data packets (larger) are silently dropped. Confirm with the ping probe above. Lower your interface MTU or apply MSS clamping on the router.
ICMP Is Filtered, Probe Gives Nothing
Some hosts filter all ICMP. Probe a host you control, or use tracepath to a reliable destination. You can also capture live traffic with tcpdump and look for ICMP Type 3 Code 4 messages coming back:
sudo tcpdump -n 'icmp and icmp[0]=3 and icmp[1]=4'
MTU Change Doesn't Survive Reboot
You set it with ip link set (runtime only). Use the NetworkManager or systemd-networkd persistent method for your distro as described above.
VPN Traffic Still Fragmented After Setting Tunnel MTU
Double-check your overhead calculation. Capture on the physical interface with tcpdump -i eth0 -v and look for fragmented packets or ICMP fragmentation-needed messages. Also verify both tunnel endpoints agree on the MTU — a mismatch between client and server config is common.
Frequently asked questions
- Why does ping work but SSH or HTTPS fail?
- ICMP echo packets are small and pass through even with a low MTU. SSH and HTTPS use larger data packets that hit the MTU limit and get silently dropped when PMTUD is blocked, producing the classic partial-connectivity symptom.
- What is the difference between MTU and MSS?
- MTU is an interface-level limit on IP packet size (including headers). MSS is a TCP-level value negotiated in the SYN handshake that limits the data payload of each TCP segment. MSS is typically MTU minus 40 bytes of IP+TCP headers, so 1460 bytes on a standard Ethernet link.
- Do I need jumbo frames (MTU 9000)?
- Only if you're running high-throughput traffic on a controlled internal network where every switch and NIC supports them. Enabling jumbo frames on an interface connected to the internet or a network with standard switches will break connectivity.
- Does IPv6 handle MTU differently than IPv4?
- Yes. IPv6 routers never fragment packets in transit — only the source host does. This makes PMTUD mandatory for IPv6. If ICMP is filtered on an IPv6 path, fragmentation-needed messages can't get back to the source, and the connection silently fails for packets above the path MTU.
- Will lowering the MTU slow down my connection?
- Slightly — smaller MTU means more packets and more header overhead per byte of payload. In practice, the difference is negligible for most workloads. The performance cost of dropped packets and retransmissions from a broken MTU far outweighs any small overhead from a correctly set lower MTU.
Related guides
Build a Mesh VPN with Nebula
Build a fully self-hosted mesh VPN with Nebula: create a CA, sign node certs, configure lighthouses, enforce group-based firewall rules, and run as a systemd service.
Common Linux Network Ports Reference
Learn Linux port ranges, read /etc/services, find what's listening with ss and nmap, and apply solid firewall rules to expose or block the right ports.
How to Configure a Static IP on Linux
Configure a static IP on Linux using Netplan, NetworkManager (nmcli), or systemd-networkd across Ubuntu, Fedora, Debian, and Arch with verified steps.
Expose a Service with Cloudflare Tunnel
Expose local services to the internet without port-forwarding using Cloudflare Tunnel. Install cloudflared, create a named tunnel, configure ingress rules, and run as a systemd service.