Culvert VPN

UDP vs TCP for a VPN: speed versus getting through

UDP is the right transport for a VPN because it avoids stacked retransmission; TCP is the one that connects where UDP is filtered. The trade explained.

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

A VPN tunnel should run over UDP whenever the network allows it, and over TCP only when it does not. UDP lets the traffic inside the tunnel handle its own reliability, which is what it was designed to do. TCP wraps that traffic in a second reliable layer, and when a packet is lost the two layers retransmit on top of each other and the connection stalls. TCP's advantage is that it gets through networks that filter UDP, and on port 443 it can look like ordinary web traffic to a port filter.

What the two transports do

UDP sends each packet on its own. If one is lost, nothing at the UDP layer notices; it is up to whatever is inside to cope. TCP builds a stream: every byte is numbered, the receiver acknowledges what arrived, anything missing is resent, and nothing is delivered out of order.

For a web browser talking to a website, TCP's care is exactly right. For a VPN tunnel it is the wrong layer to be careful at, because the traffic inside the tunnel is already mostly TCP and already doing that work.

Stacked retransmission

Put a TCP connection inside a TCP tunnel and lose one packet on the way. The outer tunnel notices the gap and holds everything behind it until the retransmission arrives. Meanwhile the inner connection, which has also stopped seeing acknowledgements, starts its own retransmission timer. If the outer recovery is slow enough, the inner layer resends data the outer layer was about to deliver anyway, and both back off their sending rates at once. On a clean network the effect is small. On a lossy one, which describes most Wi-Fi, it turns a few percent of loss into a connection that lurches and stalls.

A UDP tunnel does not have this problem. A lost packet is simply lost, the inner TCP connection notices in the normal way, retransmits once, and carries on. The tunnel never holds anything back.

There is a second, quieter cost. Applications that use UDP themselves, such as video calls and games, choose it because they would rather skip a lost frame than wait for it. Inside a TCP tunnel they cannot skip; everything arrives in order or not at all, so a call that would have shown one glitchy frame instead freezes for the retransmission. The video calls post goes through what that looks like.

The comparison

UDP tunnelTCP tunnel
Loss handlingLeft to the traffic insideDoubled: the tunnel and the traffic inside both retransmit
OrderingNot enforcedStrict, even for traffic that does not want it
Latency added by lossSmallCan be large and bursty
Per-packet overhead8-byte UDP header20-byte TCP header plus acknowledgements the other way
Gets through a network that drops UDPNoYes
Looks like web traffic on port 443NoYes, to a port filter; with TLS, to most protocol filters too
Used byWireGuard, OpenVPN (default), IKEv2OpenVPN (option), TLS-wrapped transports

When TCP is the right answer

Some networks drop UDP outright. Others allow it only on a few ports, or throttle it, or run a filter that recognises VPN protocols by their packet shapes and quietly discards them. Hotel, campus and office Wi-Fi are the usual places. On those networks a UDP tunnel sends its handshake and gets silence back, forever. A TCP tunnel on port 443 gets through, because the network cannot block 443 without blocking the web.

If the TCP tunnel is also wrapped in TLS and presents a publicly trusted certificate, it looks like HTTPS not only to a port filter but to a filter that inspects the protocol, which is the design the VPN over TLS post describes. The post on networks that drop UDP covers how to recognise that you are on one.

How an app should choose

Not by asking you. The app can find out in a few seconds whether UDP works on the current network, because a UDP handshake that gets no reply is a clear enough signal. The right order is: try UDP, on more than one port in case only some are open; if nothing answers within a short budget, try TCP on 443; keep whichever worked. When the phone moves to a different network, start again from the top, because the new network may allow UDP where the old one did not, and UDP is the transport you want whenever it is available.

What you will notice is only this: on most networks the VPN connects almost instantly and feels like no VPN at all, and on a restrictive network it takes a little longer to connect and is a little slower once it does. The why is my VPN slow post explains how to tell that case from an overloaded server.

Culvert VPN tries WireGuard over UDP on several ports first and moves to a TLS-wrapped transport on TCP port 443 only when UDP gets no reply, choosing automatically on every network change; it is on Google Play.

Questions people also ask

Is TCP more secure than UDP for a VPN?

No. The encryption is the same either way; the transport only decides how packets are delivered. TCP is not safer, it is more reliable at the cost of speed.

Why does my VPN feel slower on TCP?

Two layers of retransmission fight each other when a packet is lost, and the tunnel has to deliver everything in order even when the app inside would rather skip ahead. Both add delay on any lossy network.

Should I set my VPN to TCP if UDP works?

No. Leave it on UDP and let the app fall back to TCP only when UDP gets no reply. A good app makes that decision on its own.