The TCP 3-Way Handshake Explained

Before TCP can transfer data, both endpoints must agree on initial sequence numbers and confirm they can both send AND receive. This negotiation is the famous 3-way handshake. It happens billions of times per second across the internet.

The three packets

Client                                 Server
   |                                      |
   |  SYN  seq=x                          |
   |─────────────────────────────────────→|
   |                                      |
   |              SYN-ACK  seq=y, ack=x+1 |
   |←─────────────────────────────────────|
   |                                      |
   |  ACK  seq=x+1, ack=y+1               |
   |─────────────────────────────────────→|
   |                                      |
   |  [connection established]            |
   |  [data can now flow]                 |

Step by step

1. Client → Server: SYN

“I want to start a connection. My initial sequence number is X.”

The SYN flag is set. The Sequence Number field has a random value (X).

2. Server → Client: SYN-ACK

“OK. I acknowledge your SYN (ACK = X+1, meaning ‘I’m expecting X+1 next’). My initial sequence number is Y.”

Both SYN and ACK flags are set. Sequence Number = Y, Acknowledgment Number = X+1.

3. Client → Server: ACK

“OK. I acknowledge your SYN (ACK = Y+1).”

ACK flag set. Sequence Number = X+1, Acknowledgment Number = Y+1.

Why three packets

You need three because each side has to:

  • Send its own initial sequence number
  • Confirm receipt of the other side’s sequence number

That’s 4 logical operations, but the server’s “send my SYN” and “ack your SYN” are combined into one packet (the SYN-ACK), giving us 3 packets total.

The latency cost: 1 RTT

Notice that no application data has been sent yet — and we’ve already used 1.5 round trips (the client sent the third ACK, then can immediately send data, so effectively 1 RTT before the first data byte).

If you’re connecting to a server 200 ms away, you’ve already waited 200 ms before HTTP can even start.

Why TLS makes it worse

HTTPS adds another 1-2 RTTs for the TLS handshake on top of TCP. So a fresh HTTPS connection costs:

TCP handshake:   1 RTT
TLS 1.2 handshake: 2 RTTs
First HTTP request: ½ RTT
Total before first byte: ~3.5 RTTs

At 100 ms RTT, that's 350 ms before any content arrives.
At 300 ms RTT (mobile in remote area), 1+ second.

TLS 1.3 cuts this to 1 RTT. QUIC (HTTP/3) gets it down to 0 RTT for repeat connections by combining handshakes.

Connection teardown: 4 packets

Closing a connection takes a 4-way handshake (FIN, ACK, FIN, ACK):

Client                          Server
  | FIN  →                         |
  |       ←  ACK                   |
  |       ←  FIN                   |
  | ACK  →                         |
  |  [connection closed]           |

SYN flood attack

Because servers must allocate state when they receive a SYN (to track the half-open connection), an attacker can flood SYNs without responding. Server resources fill up. Defense: SYN cookies — the server doesn’t allocate state until it receives the final ACK.

# Enable SYN cookies (already on by default in modern Linux)
sysctl net.ipv4.tcp_syncookies   # should be 1

Watch a handshake live

# In one terminal, listen on port 8000
nc -l 8000

# In another, capture the handshake
sudo tcpdump -i lo -nn 'tcp port 8000' -c 6

# In a third, connect
nc localhost 8000

# tcpdump shows: SYN, SYN-ACK, ACK, then your data

What to learn next

Ports and sockets — the addressing system within an IP that tells the kernel which application gets which packet. Up next.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *