TCP Three-Way Handshake: How Connections Are Established
The TCP three-way handshake is a process where a client and server exchange SYN and ACK packets to establish a reliable connection before data transfer begins.
TCP Three-Way Handshake
Before two devices exchange any data over TCP, they need to agree to talk. The three-way handshake is how that agreement happens. It is a brief but essential exchange of three messages that establishes a reliable, synchronised connection with agreed sequence numbers before a single byte of application data can flow.
Why a Handshake Is Needed
TCP guarantees reliable, ordered delivery of data. To fulfil that guarantee, both sides of a connection need to know several things before data can flow. They need to confirm that the other side is reachable and ready to receive. They need to agree on starting sequence numbers so that both sides can track which bytes have been sent and received and detect when something goes missing. And they need to establish that the communication channel works in both directions, not just from sender to receiver.
The three-way handshake achieves all of this in exactly three message exchanges, adding one round-trip time of latency before any application data flows. It is the minimum number of steps required to satisfy all of these requirements simultaneously. Two steps would leave one direction unconfirmed. Four steps would be redundant. Three is the mathematically minimal solution.
The Three Steps in Detail
| Step | From | To | Message | What It Means |
|---|---|---|---|---|
| 1 | Client | Server | SYN | "I want to open a connection. My starting sequence number is X. Are you there and ready?" |
| 2 | Server | Client | SYN-ACK | "I received your SYN and acknowledge sequence X+1. I also want to connect. My starting sequence number is Y." |
| 3 | Client | Server | ACK | "I received your SYN and acknowledge sequence Y+1. The connection is now open on both sides." |
Client Server
| |
|------- SYN (seq=100) ------------>| Step 1: Client initiates
| [Client: SYN_SENT] | Server: allocates connection resources
| |
|<-- SYN-ACK (seq=200, ack=101) ----| Step 2: Server acknowledges and responds
| [Server: SYN_RECEIVED] |
| |
|------- ACK (ack=201) ------------>| Step 3: Client acknowledges server
| [Client: ESTABLISHED] | [Server: ESTABLISHED]
| |
|====== Data can now flow ==========|
| |
| GET /index.html HTTP/1.1 --------> |
| <-------- 200 OK + HTML ----------|
What SYN, ACK, and Sequence Numbers Mean
Understanding the terminology in the handshake helps you read network diagnostic output and reason about what went wrong when connections fail to establish.
- SYN (Synchronise): A control flag in the TCP header that signals the start of a new connection. When set, it indicates that the sender is proposing a new connection and sharing its initial sequence number. Only the first packet in a connection has SYN set without ACK. The second packet has both SYN and ACK set.
- ACK (Acknowledge): A control flag confirming receipt of data. The acknowledgement number field carries the value of the next expected sequence number from the other side, which implicitly confirms that all bytes up to that point have been received. Once the connection is open, virtually every TCP segment has ACK set.
- Sequence number: A 32-bit counter that tracks the byte position of each segment within the data stream. Each side generates a random initial sequence number (ISN) to prevent conflicts with previous connections on the same port. As data is transmitted, the sequence number advances by the number of bytes sent. This is how TCP detects missing data and ensures correct ordering at the destination.
- ISN (Initial Sequence Number): The randomly chosen starting value for a connection's sequence counter. Using a random ISN rather than always starting at zero prevents packets from an old connection being mistaken for packets from a new one on the same port, and makes it harder for attackers to forge TCP packets.
TCP Connection States
During and after the handshake, both the client and server track the state of the connection through a defined state machine. Understanding these states helps when reading network diagnostic tools like netstat or ss.
| State | Side | Meaning |
|---|---|---|
| LISTEN | Server | Waiting for an incoming connection request. The server is ready and listening on a port. |
| SYN_SENT | Client | SYN has been sent. Waiting for a SYN-ACK from the server. |
| SYN_RECEIVED | Server | SYN has been received and SYN-ACK has been sent. Waiting for the client's final ACK. |
| ESTABLISHED | Both | Connection is fully open. Data can flow in both directions. |
| FIN_WAIT_1 | Initiator | The side initiating close has sent FIN and is waiting for acknowledgement. |
| CLOSE_WAIT | Receiver | FIN has been received. Waiting for the application to finish and close its side. |
| TIME_WAIT | Initiator | Both FINs have been exchanged. Waiting to ensure the final ACK was received before releasing the port. |
| CLOSED | Both | Connection is fully terminated. The port is free. |
What Happens After the Handshake
Once the third step of the handshake is complete, both sides are in the ESTABLISHED state and application data can flow. For an HTTPS web page load, this is when the browser sends the HTTP GET request and the server begins returning HTML, CSS, JavaScript, and other resources.
The sequence and acknowledgement numbers continue to advance throughout the data transfer. Every segment the server sends increments its sequence counter by the number of bytes in the payload. Every segment the client receives is acknowledged with an ACK containing the next expected sequence number. This continuous exchange is how TCP tracks what has been received and detects when a retransmission is needed.
When both sides are finished exchanging data, TCP closes the connection through a four-step exchange called the FIN-ACK sequence. The side that wants to close first sends a FIN packet. The other side acknowledges it, finishes sending any remaining data, and then sends its own FIN. The first side acknowledges that FIN and enters the TIME_WAIT state before the connection is fully released.
Client Server
| |
|-------- FIN (seq=500) ----------->| Client: "I'm done sending."
| |
|<-------- ACK (ack=501) -----------| Server: "Acknowledged. Still sending..."
| |
|<-------- FIN (seq=800) -----------| Server: "I'm done too."
| |
|-------- ACK (ack=801) ----------->| Client: "Acknowledged."
| [Client: TIME_WAIT] |
| [Server: CLOSED] |
| |
| [Client: CLOSED after timeout] |
How the Handshake Affects Web Performance
The three-way handshake adds one full round-trip time (RTT) of latency before any application data can be exchanged. For a server geographically close to the user, this might be 5 to 20 milliseconds. For a server on the other side of the world, it could be 150 to 300 milliseconds. This overhead is paid once per new TCP connection, which is why connection reuse is so valuable for web performance.
- HTTPS requires a TLS handshake on top of the TCP handshake: Before any encrypted content can be exchanged, the browser and server must negotiate TLS parameters, exchange certificates, and derive shared encryption keys. This adds one to two additional round trips after the TCP handshake completes, meaning an initial HTTPS connection to a distant server can easily take 300 to 500 milliseconds before the first byte of content arrives.
- HTTP/1.1 keep-alive reuses connections: By default, HTTP/1.1 keeps the TCP connection open after each request so subsequent requests can skip the handshake. This was a significant improvement over HTTP/1.0, which closed the connection after every response.
- HTTP/2 multiplexes multiple requests on one connection: Rather than opening parallel TCP connections for each resource, HTTP/2 sends multiple requests simultaneously over a single established connection, paying the handshake cost only once per origin.
- HTTP/3 with QUIC merges handshakes: QUIC, the transport protocol behind HTTP/3, combines the connection establishment and TLS handshake into a single round trip. For connections to previously visited servers, QUIC can use zero round-trip resumption, allowing data to be sent before any handshake response is received.
- Connection preconnect hints: The HTML
<link rel="preconnect">hint instructs the browser to perform the TCP and TLS handshake to a specified origin in advance, before the browser discovers it needs to make a request there, eliminating the handshake latency from the critical path.
SYN Flood Attack
A SYN flood is a denial-of-service attack that exploits the three-way handshake. The attacker sends a large volume of SYN packets to the target server, often with spoofed source IP addresses, but never sends the final ACK to complete the handshake. The server allocates resources for each half-open connection and enters the SYN_RECEIVED state, waiting for an ACK that never arrives. If enough SYN packets arrive, the server's half-open connection table fills up and it begins rejecting legitimate connection attempts.
Several defences exist against SYN flood attacks. SYN cookies allow the server to avoid allocating resources until the handshake is complete. Instead of storing the half-open connection in a table, the server encodes the connection information in a cryptographic value embedded in the SYN-ACK's sequence number. When the client's ACK arrives, the server reconstructs the connection state from that value. Network-level rate limiting and firewall rules can also detect and block SYN floods by identifying abnormally high rates of SYN packets from a single source.
Diagnosing Connection Issues with Common Tools
Several command-line tools let you observe the TCP handshake and connection states in practice, which is useful for diagnosing why connections are failing or slow.
# View all active TCP connections and their states
netstat -an | grep TCP
# Modern alternative to netstat on Linux
ss -tan
# Trace the TCP handshake in detail (requires root/admin)
# Shows SYN, SYN-ACK, ACK packets and their sequence numbers
tcpdump -n 'tcp[tcpflags] & (tcp-syn|tcp-ack) != 0' -i eth0
# Measure connection time including handshake latency
curl -w "TCP handshake: %{time_connect}s\nTotal: %{time_total}s\n" \
-o /dev/null -s https://example.com
# Test whether a specific port is reachable (performs the handshake)
telnet example.com 443
nc -zv example.com 443
Frequently Asked Questions
- Why three steps and not two?
Two steps would only verify communication in one direction. After the client sends SYN and the server responds with SYN-ACK, the server knows it can receive from and send to the client. But the client has not yet confirmed it can receive from the server, and the server does not know whether its SYN-ACK was received. The client's final ACK in step three confirms both that the server's response arrived and that the server's sequence number was received correctly. Both directions must be verified for TCP's reliability guarantees to hold, and three steps is the minimum required to achieve this. - Does every web request perform a handshake?
Not necessarily. HTTP keep-alive, which is the default in HTTP/1.1, reuses an established TCP connection for multiple requests, avoiding a new handshake for each one. HTTP/2 goes further by multiplexing many requests simultaneously over a single connection. HTTP/3 over QUIC can reuse connection state across sessions for zero round-trip connection establishment on repeat visits. A new handshake is only required when connecting to an origin for the first time in a session or when a previous connection has been closed due to inactivity or timeout. - Does UDP have a handshake?
No. UDP is connectionless and sends packets immediately without any setup exchange. This is a primary reason why UDP is faster than TCP for latency-sensitive applications, but it also means UDP provides no delivery guarantees, no ordering, and no confirmation that the other side received anything. Applications that need some reliability on top of UDP, such as those using QUIC, must implement their own acknowledgement mechanisms at the application layer. - What happens if the server does not respond to a SYN?
If the client sends a SYN and receives no SYN-ACK in return, the TCP stack waits for a timeout period and then retransmits the SYN. This retransmission uses an exponential backoff strategy, waiting progressively longer between each attempt. After a configured number of retransmission attempts, typically around 5 to 6 by default on most operating systems, the connection attempt is abandoned and the calling application receives a connection timeout error. The total time before giving up is usually between 75 seconds and several minutes, though this is configurable. - What is a half-open connection and why does it matter?
A half-open connection is one where the three-way handshake has been initiated but not completed. After the server sends its SYN-ACK, it enters the SYN_RECEIVED state and allocates resources for the connection while waiting for the client's ACK. If the client never sends the ACK, the server holds that half-open connection until a timeout clears it. Under normal circumstances this is harmless, but a SYN flood attack deliberately creates thousands of half-open connections simultaneously to exhaust the server's connection table, preventing legitimate connections from being accepted. SYN cookies were invented specifically to allow servers to handle SYN floods without maintaining state for half-open connections.
Conclusion
The TCP three-way handshake is a brief but critical process that establishes the synchronised, bidirectional, reliable connection that TCP depends on before any application data can flow. It confirms reachability in both directions, synchronises sequence numbers for ordered delivery, and sets the foundation for everything from a simple HTTP request to a long-lived SSH session. The one round-trip latency cost it adds is the price of TCP's reliability guarantee, and the innovations in HTTP/2, HTTP/3, and QUIC are largely focused on reducing or eliminating that cost while preserving the reliability that applications depend on. Understanding the handshake helps you diagnose connection failures, interpret network diagnostic output, and reason about why web performance optimisations like connection reuse and preconnect hints have the impact they do. Continue with TCP vs UDP, HTTP vs HTTPS, and SSL and TLS to build a complete understanding of how reliable connections are established and secured on the web.
