Every guide says UDP beats TCP for OpenVPN, and that advice is a default rather than a measurement. The transport changes how packets are delivered and what happens when the path drops them, not how the tunnel is encrypted. Behind a captive portal or a proxy that only permits port 443, the slower option is the one that connects at all. What follows separates what the protocol does from what your access network allows.

What the Transport Actually Changes

TCP delivers a reliable ordered byte stream and retransmits whatever is lost, as RFC 9293 specifies. UDP hands datagrams to the network, and OpenVPN runs its own reliability layer over that socket. Encapsulating TCP inside TCP stacks two recovery loops, so one lost segment can hold up the inner stream until the outer retransmission lands. That interaction is the real argument for UDP, and it appears as latency rather than as throughput.

The effect scales with loss and round-trip time. On a clean local path both transports feel identical, which is why a benchmark in a lab rarely reproduces the complaint. On a congested mobile link the difference shows up in interactive sessions long before a bulk transfer notices anything.

None of this touches confidentiality or integrity. The TLS handshake and the data-channel cipher are the same for both transports, so switching cannot rescue a weak cipher suite.

Where TCP Earns Its Place

Access networks are the usual reason to choose TCP. A hotel, an airport or a guest network may allow outbound 443 and drop everything else, and a TCP listener on that port is the only profile that works. That is reachability rather than performance, and it is a good enough reason on its own.

TCP also helps when the path is stable but the middleboxes are hostile. Some networks reset long-lived UDP flows while tolerating TCP sessions that resemble ordinary web traffic. Whether that resemblance succeeds is a property of the specific network, and no guide can promise it for all of them. Test inside the network that fails before blaming the protocol.

A rejected login is not a transport problem. Disabling certificate verification to force a connection through is a different change with a much worse outcome.

Keeping a TCP profile ready is the practical compromise. Most clients store both and let you switch when a network refuses the UDP path, which costs nothing until you need it. What you should not do is ship two profiles pointing at different endpoints, because then your comparison measures the servers.

Check Which Listener You Actually Have

Before comparing performance, confirm both ends agree on the transport and the port. Editing proto udp to proto tcp in a client file does not create a server listener. The server has to be configured for that protocol, and the profile has to match it.

grep -E '^(proto|port|remote)' /etc/openvpn/server.conf
ss -lunp | grep openvpn
ss -ltnp | grep openvpn

The grep prints what the server was told to use, while the two socket listings show what it is bound to. A UDP listener appears only in the first listing and a TCP listener only in the second, so a missing line is the quickest way to find a profile that was never applied. Compare the port as well, since a TCP profile on 1194 behaves differently from one on 443 in most access networks. Restart the service after the change and read the log line that reports the binding.

Client-side confirmation is cheap: run the connection with --verb 4 and read the transport line in the log. If the client says UDP while the server listens on TCP, the handshake never starts and no amount of tuning will help.

Compare the Workload, Not the Transport Label

A fair comparison holds everything except the transport constant. Same device, same access network, same destination host, same application, and ideally the same server. If the two profiles point at different hosts, you are measuring those hosts as well.

Record three outcomes for each run: whether the tunnel establishes, whether it stays up, and whether the task completes. Small requests that work while large transfers stall point at packet size and MTU rather than at the transport. Repeated reconnects point at the path or at a middlebox timeout.

Keep the profile that works under the conditions you actually meet, and keep the other one saved. The choice belongs to the network, not to the person, which is why any single default answer is wrong somewhere.

Qillqakuna t'inkisqa