Where TCP and UDP sit
The internet protocol stack is layered. IP at the bottom knows how to route a packet from one host to another, but nothing more — no concept of applications, no guarantees about delivery, no notion of ordering. On top of IP sit the two workhorse transport protocols: TCP (Transmission Control Protocol) and UDP (User Datagram Protocol).
Everything above the transport layer — HTTP, DNS, SSH, SMTP, video calls, online games — picks one of these two as its delivery mechanism. The choice shapes how the application feels: whether it stalls when a packet is lost, how fast it connects, how it behaves on a flaky mobile network. Understanding TCP vs UDP is understanding why some services feel snappy and others feel sluggish under the exact same network conditions.
TCP in one paragraph
TCP is a connection-oriented, reliable, ordered byte stream. Before any data flows, the two endpoints perform a three-way handshake: SYN from the client, SYN-ACK from the server, ACK back from the client — one full round trip (1 RTT) before the first byte of payload can move. Once the connection is established, TCP numbers every byte, retransmits anything that isn't acknowledged, reorders out-of-order arrivals, and applies flow control (so a fast sender doesn't drown a slow receiver) and congestion control (so it backs off when the network is overloaded). When you're done, a FIN exchange tears the connection down cleanly. The base header is 20 bytes, before options.
UDP in one paragraph
UDP is the opposite philosophy: send a packet, hope it arrives, move on. There is no handshake, no connection state, no ordering, no retransmission, no flow control, no congestion control. You hand UDP a datagram with a destination IP and port; it slaps an 8-byte header on the front and shoves it onto the wire. If it gets lost, you don't find out — unless you build that logic yourself in the application. The header is just four fields: source port, destination port, length, checksum. 8 bytes total, versus TCP's 20. That smaller header and the absence of handshake overhead are exactly why UDP exists.
Head-of-line blocking
TCP's biggest hidden cost is head-of-line blocking. Because TCP guarantees in-order delivery, if packet 5 is lost, packets 6, 7, and 8 sit in the receiver's buffer doing nothing — even though they've arrived — until packet 5 is retransmitted and arrives. The application sees a stall. For a file download this is fine: you waited a few extra milliseconds. For a video call or a live game, that stall is a freeze, a glitch, a missed input.
UDP has no such constraint. If packet 5 is lost, packets 6, 7, and 8 are still delivered immediately to the application, which decides for itself what to do — interpolate, drop, request a resend, whatever fits. The application owns the policy. This is the core reason real-time protocols choose UDP: they would rather lose a packet than wait for it.
When TCP is the right choice
TCP is the default for anything where correctness matters more than latency:
- Web browsing (HTTP/1.1 and HTTP/2) — you cannot have a half-loaded JavaScript file.
- Email (SMTP, IMAP, POP3) — every byte of every message has to land intact.
- File transfer (FTP, SFTP, SCP, rsync over SSH) — same reason.
- Remote shell (SSH on port 22) — dropped keystrokes are not acceptable.
- Databases (MySQL 3306, Postgres 5432) — transactional integrity depends on every byte arriving.
In all of these the application would have to reinvent reliability on top of UDP anyway, and would do a worse job of it than TCP, which has had 40+ years of careful tuning of congestion control algorithms (Reno, Cubic, BBR).
When UDP is the right choice
UDP wins whenever the cost of waiting exceeds the cost of a lost packet:
- DNS on port 53 — queries are tiny, a single round-trip TCP setup would more than double the time. (See What is DNS?.)
- NTP (time sync) on port 123 — handshake latency would corrupt the time measurement.
- VoIP, video calls, WebRTC — a 200 ms stall to retransmit a missing audio frame is worse than just dropping it.
- Online gaming state updates — yesterday's player position is useless; just send today's.
- STUN / TURN on port 3478 for NAT traversal — connectionless probing is the whole point.
- DHCP, mDNS, SNMP — broadcast and discovery protocols that have no concept of a "connection."
An honest caveat for gaming: the realtime state channel is UDP, but most online games also run a parallel TCP control channel for things where correctness does matter — chat, matchmaking, login, inventory, in-game purchases. It's rarely UDP-only.
Protocols that use each
| Protocol | Port | Transport | Why |
|---|---|---|---|
| HTTP/1.1, HTTP/2 | 80 / 443 | TCP | Reliable byte stream needed for HTML, JS, CSS, images. |
| HTTP/3 (QUIC) | 443 | UDP | Reliability built into QUIC; avoids TCP head-of-line blocking. |
| DNS | 53 | UDP (TCP fallback) | Small queries, latency-sensitive. Falls back to TCP for large responses or zone transfers. |
| SSH | 22 | TCP | Every keystroke must be ordered and intact. |
| SMTP / IMAP | 25 / 143 | TCP | Mail must arrive whole. |
| NTP | 123 | UDP | Time-critical, handshake would skew the measurement. |
| DHCP | 67 / 68 | UDP | Broadcast — no connection to establish. |
| VoIP (RTP) | varies | UDP | Late audio is worse than missing audio. |
| WireGuard VPN | varies | UDP | Tunnels its own reliability; UDP avoids TCP-in-TCP performance disaster. |
| OpenVPN | 1194 | UDP (TCP option) | UDP preferred; TCP mode exists only for restrictive firewalls. |
QUIC, HTTP/3, and the web migration
For the first 30 years of the web, HTTP rode on TCP. That ended with QUIC — a transport protocol Google designed and the IETF standardised, which runs on top of UDP and reimplements reliability, ordering, congestion control, and TLS encryption inside itself. HTTP/3 is just HTTP semantics running over QUIC.
Why bother? Three big wins:
- Faster connection setup. TCP needs 1 RTT for the handshake, then TLS 1.3 adds another 1 RTT (or 2 with older TLS). QUIC folds transport and crypto into 1 RTT for a new connection, and 0 RTT for a resumed one. On a 100 ms link that's a quarter-second saved on every fresh connection.
- No head-of-line blocking between streams. HTTP/2 multiplexes many requests over one TCP connection — but one lost packet stalls all of them. QUIC's streams are independent at the transport layer; a lost packet only stalls the stream it belongs to.
- Connection migration. QUIC connections survive an IP change (Wi-Fi to cellular), because the connection ID isn't tied to the IP address. TCP can't do this.
Firewall and NAT considerations
TCP is the friendlier protocol for firewalls and NAT routers, because the connection has obvious state: SYN opens it, FIN or RST closes it. A NAT box can confidently track which internal host owns which outbound flow, and stale entries are obvious.
UDP has no connection, so NAT routers have to invent one — they remember the (source IP, source port, destination IP, destination port) tuple for some short timeout (often 30 seconds for UDP versus minutes-to-hours for TCP), and forget it if no traffic flows. This is why VoIP and game clients send periodic keepalive packets: to keep the NAT pinhole open. It's also why STUN and TURN exist — explicit machinery to discover and punch holes through NAT for UDP.
Restrictive corporate firewalls often block all outbound UDP except DNS, which is why protocols like OpenVPN ship a TCP mode and why HTTP/3 always falls back to HTTP/2 over TCP if UDP 443 is blocked. The web still works; it's just slower.
Try it yourself
You can probe TCP services directly from your browser using the check.systems port scanner — it performs a TCP connect scan, so any TCP service that's listening will show as open. The common ports reference tells you which well-known service lives on which port. If you're new to scanning, the port scanner guide walks through what "open / closed / filtered" actually means.
Probing UDP is genuinely harder. Because UDP has no handshake and no required response, a "no reply" could mean the port is open and the service simply chose not to answer, or it could mean the port is closed and the host suppressed the ICMP unreachable, or it could mean a firewall ate the packet. UDP scanning takes longer (timeouts on every port) and the results are inherently ambiguous — which is why most online scanners, including this one, focus on TCP. For UDP probing, use nmap -sU locally, and be prepared to interpret the results carefully.
Related: Port Scanner tool · Common ports reference · How to use a port scanner · What is DNS?