Skip to content

TCP Three-Way Handshake

Last updated:

Before a single byte of application data moves, TCP performs a three-packet exchange that synchronizes sequence numbers in both directions. Every web request, SSH session, and BGP peering starts exactly like this.

The exchange

Step by step:

  1. SYN — the client picks a random initial sequence number x and asks to synchronize. It also advertises its window size and options (MSS, SACK, window scaling).
  2. SYN-ACK — the server acknowledges x+1 ("I have your number") and picks its own initial sequence number y.
  3. ACK — the client acknowledges y+1. Both sides now agree on both sequence spaces, and the connection is ESTABLISHED.

Why three packets and not two? Because reliability must work both ways: each side has to prove it received the other's initial sequence number. Two packets would only confirm one direction.

TCP flags cheat sheet

FlagNameSet when…
SYNSynchronizeOpening a connection (first two packets only)
ACKAcknowledgmentPractically every packet after the first SYN
FINFinishGraceful close — each side sends its own FIN
RSTResetAbort: closed port, half-open teardown, policy
PSHPushDeliver to the application without buffering
URGUrgentRare today; urgent pointer is valid

Seeing it in tcpdump

bash
$ tcpdump -n -i en0 'tcp port 443 and host example.com'

IP 192.168.1.10.54321 > 93.184.216.34.443: Flags [S],  seq 1201375243, win 65535, options [mss 1460,sackOK,TS], length 0
IP 93.184.216.34.443 > 192.168.1.10.54321: Flags [S.], seq 3630864200, ack 1201375244, win 65535, length 0
IP 192.168.1.10.54321 > 93.184.216.34.443: Flags [.],  ack 3630864201, win 2058, length 0

[S] is SYN, [S.] is SYN-ACK (tcpdump shows ACK as a dot), [.] is the final ACK. Note each ack value is the peer's seq + 1.

The full TCP state machine (expand)

The handshake is just the top of TCP's connection state machine:

TIME_WAIT lingering for 2×MSL (often 60s) is why a busy client can exhaust ephemeral ports — and why SO_REUSEADDR exists.

SYN floods

An attacker who sends SYNs and never completes step 3 fills the server's half-open connection queue — a classic DoS. Modern stacks mitigate with SYN cookies: the server encodes the connection state into its sequence number y instead of allocating memory, and only commits resources when the final ACK proves the client is real.