Culvert VPN

MTU and VPNs: why some sites load and some hang

A VPN shrinks the largest packet a connection can carry. Set that MTU too high and small pages load while large ones hang. What MTU is and what fixes it.

Protocols and the technology · 4 min read · By Culvert VPN

MTU, the maximum transmission unit, is the largest packet a network link will carry, and on most networks it is 1500 bytes. A VPN adds its own headers to every packet, so the packets inside the tunnel have to be smaller: 1420 bytes for WireGuard over UDP, about 1280 for a tunnel wrapped in TLS over TCP. When the tunnel's MTU is set higher than the path can really carry, small packets get through and large ones are silently dropped, which is why a VPN with an MTU problem loads a search page fine and hangs on an image-heavy one.

Where the numbers come from

A packet inside a WireGuard tunnel is wrapped, in order, in a WireGuard data header, a UDP header and an outer IP header. On IPv6 those add up to 80 bytes: 32 for WireGuard, 8 for UDP, 40 for IPv6. Subtracting 80 from a 1500-byte link gives 1420, which is WireGuard's default and leaves the same figure working whether the outer connection is IPv4 or IPv6.

A TLS-wrapped transport on TCP costs more: a TCP header of at least 20 bytes, a TLS record header, the record's authentication tag, and the outer IP header, on top of the tunnel's own framing. The exact figure varies with the design, and the safe answer is 1280, because 1280 bytes is the minimum every IPv6 link is required to carry, so no path between your phone and the server can be smaller. The VPN over TLS post covers the rest of what that transport costs.

TransportOuter headersTunnel MTU on a 1500-byte link
No VPNNone1500
WireGuard over UDP80 bytes on IPv6, 60 on IPv41420
IKEv2/IPsecESP, UDP encapsulation and IP; varies with cipherRoughly 1400
Tunnel inside TLS over TCPTCP, TLS record, IP, plus tunnel framingAbout 1280

What goes wrong when it is too high

Suppose a tunnel is set to 1500 when the path can only carry 1420 inside it. A small packet, a DNS reply or a page's HTML, fits and arrives. A full-sized packet, part of an image or a video segment, is 1500 bytes before the tunnel wraps it and 1580 after, which is too large for the network. The router that cannot forward it is supposed to send back an ICMP message saying "too big, use this size instead", and the sender then shrinks its packets. That mechanism is called path MTU discovery.

It fails constantly, because many networks and firewalls drop ICMP on principle. The oversized packet vanishes, no message comes back, the sender retransmits the same oversized packet, and it vanishes again. The connection stalls exactly at the point the first large packet was sent. The symptoms are distinctive:

  • Websites with little content load; heavy pages stop partway.
  • Pings and small requests work; downloads start and hang.
  • Some sites work perfectly and others never finish, depending on how they size their packets.
  • Everything works with the VPN off.

The connected-but-no-internet post lists this beside its other causes, and this is the one to suspect when the failure depends on which site you visit.

What goes wrong when it is too low

Setting the MTU too low never breaks anything, it only costs throughput. Every packet carries the same headers, so smaller packets mean a larger share of each is overhead, and the phone and server process more packets for the same data. Dropping from 1420 to 1280 loses roughly ten percent of the payload per packet. That is a small price on a network that would otherwise stall, and an unnecessary one on a network that would have carried 1420, which is why the figure should match the transport rather than always being the safe minimum.

Two fixes that work

Set the tunnel MTU correctly for the transport. This is the app's job. When it creates the VPN interface it tells Android the MTU, and Android sizes every packet it hands to the tunnel accordingly. 1420 for WireGuard over UDP, about 1280 for the TLS transport, and a different figure again for IKEv2, whose overhead depends on the cipher.

Clamp the TCP MSS. Most traffic is TCP, and every TCP connection announces the largest segment it will accept when it opens. A tunnel endpoint can rewrite that announcement downward so both ends agree on packets that fit, without relying on ICMP at all. Servers commonly do this on the tunnel interface, which protects clients whose MTU is slightly wrong.

Neither fix helps traffic that is not TCP and does not do its own discovery, which is why the first fix matters more than the second.

What you can do on Android

Very little directly, and that is fine. Android exposes no MTU setting for a VPN interface to the user; the app that creates the tunnel sets it. If you see the symptoms above, the useful steps are to reconnect, which may land you on a different transport with a different MTU, and to try a different network, since a path with an unusually small MTU, such as some mobile carriers or a PPPoE home connection, will show the problem on one network and not another. The why is my VPN slow post covers how to tell an MTU problem from a plain slow server.

Culvert VPN sets the tunnel MTU for the transport it lands on, 1420 for WireGuard over UDP and a lower figure for its TLS transport on port 443, so the same tunnel carries full-sized traffic on an open network and fits inside the extra headers on a restrictive one; it is on Google Play.

Questions people also ask

What MTU should a VPN use?

1420 is right for WireGuard over UDP on a 1500-byte network, and about 1280 for a tunnel wrapped in TLS over TCP. 1280 is the safe floor on any path, because every IPv6 link must carry it.

Why does a lower MTU fix things but make the VPN slower?

Smaller packets mean more packets, and more headers, for the same data. The loss is a few percent of throughput; the gain is that large transfers stop stalling.

Can I change the MTU myself on Android?

Not for a VPN app's tunnel; the app sets it when it creates the interface. A well-built app chooses the figure for each transport, so you should not need to.