All articles
speed-mtu
2026-08-0612 min read

WireGuard optimal MTU, derived not guessed

Stop copying 1420. Derive the WireGuard overhead byte by byte, then measure your own path MTU with one ping command on Windows, macOS or Linux.

Every page that answers the WireGuard optimal MTU question hands you a number. Usually 1420, sometimes 1380, sometimes 1280. A number is the wrong shape of answer, because the correct value depends on a link you have and the author does not. What you actually need is the arithmetic behind those numbers and a way to measure your own path. Both are below, and both are short. Derive the overhead first, then measure, then set the value once.

What MTU actually breaks

An MTU that is too large does not break the tunnel. The handshake completes, wg show reports a recent handshake, and the counters move. Small things work perfectly. Large things stall.

That combination is what makes MTU hard to recognise:

  • SSH sessions connect and then freeze the moment a command prints a screenful of output.
  • Web pages load their HTML and hang on a large image.
  • File uploads start, transfer a few hundred kilobytes, and stop.
  • One direction is fine while the other direction is unusable.

The mechanism is the same in every case. Your tunnel accepts a packet up to its configured MTU, wraps it, and hands the result to the underlying link. If the wrapped packet is larger than the link will carry, it is dropped. Small packets are under the limit and pass, so the connection looks alive the whole time.

Why 1420 is a starting point and not an answer

Build the number rather than copying it. Start with the link.

A standard Ethernet link carries a 1500-byte IP packet. That is the outer budget, and everything WireGuard adds comes out of it.

WireGuard puts your inner packet inside a UDP datagram. Four fixed costs sit between the inner packet and the link.

LayerIPv4 outer pathIPv6 outer pathWhere the number comes from
Outer IP header2040An IPv4 header without options is 20 bytes. The fixed IPv6 header is 40 bytes.
UDP header88Source port, destination port, length and checksum, at 2 bytes each.
WireGuard data message header16161 byte message type, 3 bytes reserved, 4 bytes receiver index, 8 bytes counter.
Poly1305 authentication tag1616The tag the ChaCha20-Poly1305 AEAD appends to every encrypted payload.
Total overhead6080

Add the columns. 20 + 8 + 16 + 16 = 60 on IPv4, and 40 + 8 + 16 + 16 = 80 on IPv6.

Subtract each from the link:

IPv4 outer path:  1500 - 60 = 1440
IPv6 outer path:  1500 - 80 = 1420

There is 1420. It is not a tuned value and it is not a benchmark result. It is the IPv6 column, and it is the default because it is the conservative one. A tunnel set to 1420 fits whichever address family your Endpoint resolves to, which is why every article repeats it.

wg-quick reaches it the same way. Its manual page says only that the MTU is automatically determined from the endpoint addresses or the system default route. The Linux implementation is more specific than that. It takes the smallest MTU among the routes to its endpoints, falls back to the default route, falls back again to 1500, and subtracts 80. The 80 is a constant. It does not drop to 60 for an IPv4 endpoint. An IPv4 tunnel left on the default therefore gets the IPv6 answer and gives up 20 bytes of payload.

The 16-byte term nobody counts

WireGuard pads the inner packet with zeros before it encrypts, so that the plaintext length is a multiple of 16 bytes. The protocol specification is explicit about it: the encapsulated packet is followed by "zero padding in order to make the length a multiple of 16".

That padding is part of the outer packet, so it belongs in the sum. The full expression for an inner packet of L bytes is:

outer IP header + 8 + 16 + roundup16(L) + 16

Run it at L = 1420 on an IPv6 outer path. 1420 divided by 16 is 88.75, so the padded length is 89 x 16 = 1424.

40 + 8 + 16 + 1424 + 16 = 1504

1504 is four bytes over a 1500-byte link. Apply the same arithmetic in reverse to find the value that does fit. The largest multiple of 16 at or below 1420 is 1408:

40 + 8 + 16 + 1408 + 16 = 1488

The IPv4 column is tidier. 1440 is 90 x 16 exactly, so it needs no padding at all:

20 + 8 + 16 + 1440 + 16 = 1500

Treat that as the honest status of 1420. It is a sound rounding, it is correct for almost all traffic, and it is four bytes optimistic for a maximum-size packet on an IPv6 endpoint.

Be careful about what that does and does not tell you. The arithmetic is derived, and the runtime consequence is not. Whether those four bytes are fragmented, dropped or absorbed depends on the implementation you are running. Measure your own path with the method below rather than reasoning about the last four bytes.

Common values and where they come from

Use this when ICMP is filtered and you cannot measure. Every row states its arithmetic, and the two rows that have none say so.

MTUArithmeticThe path it fits
14401500 - 60Plain Ethernet, Endpoint resolving to an IPv4 address
14321492 - 60PPPoE line, IPv4 endpoint
14201500 - 80Plain Ethernet, IPv6 endpoint. The conservative default, correct either way
14121492 - 80PPPoE line, IPv6 endpoint
1408largest multiple of 16 at or below 1420Exact fit on an IPv6 endpoint once the 16-byte padding is counted
1400noneA round number widely reported to work. Empirical, not derived
13801460 - 80DS-Lite or any path carrying one extra 40-byte encapsulation
1280noneThe minimum link MTU every IPv6 path is required to carry. A floor, not an optimum

Spell out the caveat on the two rows with no arithmetic. 1400 is the value that appears in most forum threads, and it works because it is comfortably under every common limit rather than because it fits one. 1280 is a floor. It is the smallest MTU any IPv6 link is permitted to have, so a tunnel set to 1280 passes almost anywhere. Expect to pay for that in more packets and more per-packet overhead for the same data.

For the wider set of tunnel settings this interacts with, see WireGuard MTU and tunnel settings.

Setting it and confirming it helped

Put the MTU line in the [Interface] section, not in [Peer]. If you do not have a config open yet, start with installing WireGuard.

[Interface]
PrivateKey = <your private key>
Address = 10.7.0.2/32
DNS = 10.7.0.1
MTU = 1420

[Peer]
PublicKey = <server public key>
Endpoint = vpn.example.com:51820
AllowedIPs = 0.0.0.0/0, ::/0

Apply it by restarting the interface, not by reloading. On Linux run wg-quick down wg0 then wg-quick up wg0. In the Windows and macOS clients, deactivate the tunnel and activate it again. Confirm the interface took the value with ip link show wg0 on Linux. On Windows and macOS, read the MTU back from the operating system rather than from the app. An app can show you what you typed rather than what the interface holds. Then repeat the transfer test below, which is the check that actually settles it.

For where to edit the file on each platform, see editing your config.

Then measure properly, because a single speed-test run proves nothing.

  • Record a baseline before you change anything, by timing the same large transfer three times.
  • Change the MTU and restart the interface.
  • Repeat the identical transfer three times.
  • Compare medians rather than best runs, and test upload and download separately.

Use a large transfer rather than a ping for the confirmation. MTU problems only appear on full-size packets, so a latency test will look identical before and after. Test both directions as well, because the classic MTU signature is one direction working and the other stalling.

Check one thing in your own file before you edit it. If the [Interface] section already carries an MTU line, change the value on that line rather than adding a second one. A config with two MTU lines behaves according to whichever the client reads last, and that is not a property you want to discover during a transfer.

What a PulseVPN config gives you to start from

A PulseVPN WireGuard config ships with no MTU = line at all. That is the useful fact here, and it has two consequences.

The first is that your client derives the value rather than reading it. On Linux wg-quick applies the rule described above, taking the route MTU to the endpoint and subtracting 80. An IPv4 endpoint therefore lands on 1420 rather than on the 1440 the arithmetic allows.

The second is that you add a line rather than editing one. Open the [Interface] section, put your measured value on its own line, and restart the interface. There is no existing value to overwrite and no duplicate to create.

The rest of the file is already populated. A PulseVPN config carries DNS = 1.1.1.1, AllowedIPs = 0.0.0.0/0, ::/0 and PersistentKeepalive = 25, so a full tunnel, a resolver and a NAT keepalive are all set for you. The MTU is the one field this page asks you to supply.

When MTU is not the problem

MTU is the first thing to check and it is not the only thing. Four other causes produce a slow tunnel and none of them respond to an MTU change.

  • Distance to the server. A single stream is bounded by round-trip time and window size. Changing MTU does not change latency.
  • Congestion on your access link. A saturated uplink is slow with and without a tunnel. Compare against the same test with the tunnel down.
  • CPU on your own device. Small routers, older phones and low-end virtual machines hit an encryption ceiling well below their line rate.
  • Capacity at the far end. The server is a shared machine with a shared uplink, and its limit is not visible from your side.

Rule each of them out with the tunnel down, then with it up, on the same test. For the wider symptom index, see connection troubleshooting. For how the protocols differ before you assume WireGuard is the constraint, see how the two protocols differ.

Quick answers

Can MTU really change throughput that much
Third-party reports say yes, where MTU is the binding constraint. User y0nei reported this on the widely cited WireGuard MTU gist: "I was getting ~35 Mbits/sec inside of my tunnel with having a MTU of 1500 both on client and server...after testing your values...im getting ~240 Mbits/sec" Treat that as one person on one link rather than as a benchmark. Measure your own before and after.
Why does a lower MTU feel faster
Because a wrongly sized packet is not slow, it is dropped. TCP then retransmits, backs off, and retries at a lower rate, so the connection stalls rather than degrades. Lowering the MTU stops the drops, and throughput returns to whatever the link supports. The same gist commenter pirmanji described the result as "my VPN has become workable and feels quite fast".
Does a VPN make internet slower
Usually a little, and rarely by much. Encryption costs CPU, the extra headers cost payload space, and routing through another city costs latency. A well-configured tunnel on a modern device gives up single-digit percentages of throughput. If yours is losing far more than that, the cause is usually MTU, distance or a saturated link rather than the protocol.
Should I set MTU on the client, the server, or both
MTU is a per-interface setting, so the client value controls only what your client emits. Setting it on the client fixes stalls in the direction you send. If the server side is also oversized, the return direction can still stall, and only the operator can change that. Set your client value from your own measurement and treat the far side as fixed.
Is WireGuard slower than OpenVPN
Sometimes, and MTU is the usual reason. WireGuard has less per-packet overhead than OpenVPN, so it should be faster on equal terms. An OpenVPN profile carrying mssfix clamps TCP segment size, which papers over a path MTU problem that a bare WireGuard config exposes instead. The OpenVPN manual gives the mssfix default as 1492 mtu, so that clamp is usually applied whether anyone chose it or not. Fix the MTU before concluding the protocol is at fault. For the settings this page sits inside, see WireGuard MTU and tunnel settings. For everything else that stalls a tunnel, see connection troubleshooting.
Put it into practice

A 24-hour PulseVPN trial takes about a minute to set up and asks for no card, no email, and no name.

Start free trial

Related reading