Every TCP connection begins with a three-way handshake. The client and server
synchronize sequence numbers before any application data flows.
The handshake as a sequence
100%
Diagram source
sequenceDiagram
autonumber
participant C as Client
participant S as Server
C->>S: SYN (seq=x)
Note right of S: LISTEN → SYN-RECEIVED
S-->>C: SYN+ACK (seq=y, ack=x+1)
Note left of C: SYN-SENT → ESTABLISHED
C->>S: ACK (ack=y+1)
Note over C,S: Connection established
Connection state machine
100%
Diagram source
stateDiagram-v2
[*] --> CLOSED
CLOSED --> SYN_SENT: active open / send SYN
CLOSED --> LISTEN: passive open
SYN_SENT --> ESTABLISHED: recv SYN+ACK / send ACK
LISTEN --> SYN_RCVD: recv SYN / send SYN+ACK
SYN_RCVD --> ESTABLISHED: recv ACK
ESTABLISHED --> FIN_WAIT_1: close / send FIN
FIN_WAIT_1 --> FIN_WAIT_2: recv ACK
FIN_WAIT_2 --> TIME_WAIT: recv FIN / send ACK
TIME_WAIT --> [*]: timeout (2*MSL)
Why three segments and not two?
A two-way handshake cannot distinguish an old duplicate SYN from a new one.
The final ACK lets the server reject stale connection attempts.
100%
Diagram source
flowchart LR
A[Old duplicate SYN] --> B{Server state?}
B -- LISTEN --> C[Would wrongly accept\nin 2-way handshake]
B -- SYN_RCVD --> D[RST: duplicate detected\n3-way handshake saves us]
Handshake timing
100%
Diagram source
gantt
title Connection establishment timeline
dateFormat X
axisFormat %L
section Client
Send SYN :active, c1, 0, 4
Wait SYN+ACK :c2, 4, 4
Send ACK :done, c3, 8, 4
section Server
Listen :s1, 0, 4
Reply SYN+ACK :active, s2, 4, 4
Established :done, s3, 8, 4
Packet capture snippet
The same exchange on the wire, captured with tcpdump:
Key insight: the handshake is not “three messages for politeness” — it is a
minimal agreement protocol that survives duplicated, delayed, and reordered
packets on an unreliable network.