Back to the map

Module 12 · Transport layer · Lesson 1 of 5

TCP handshake and teardown

How TCP opens and closes a connection: the three-way handshake and what it costs in round trips, the four-way close, TIME_WAIT and why servers accumulate it, resets, SYN floods and SYN cookies, and why connection reuse matters so much.

CoreMust-knowJunior 12 minVideo Updated Nov 2026
Video walkthrough · 2:42 · narrated, with captions

Why it matters

Every new TCP connection costs a full round trip before any data flows, and every closed one leaves state behind on one side for up to a couple of minutes. Those two facts explain why connection pooling and HTTP keep-alive matter, why a service making short-lived outbound connections runs out of ports, why a cold request to a far region is slow, and what a "connection reset by peer" actually means. The handshake is also the target of one of the oldest denial-of-service attacks.

The idea

TCP gives two programs a reliable, ordered byte stream over an unreliable network. Before sending data, both sides must agree on starting sequence numbers (so each byte can be numbered, acknowledged and reordered), so connection setup is a short negotiation.

The three-way handshake

ClientServerSYN, seq=xSYN-ACK, seq=y, ack=x+1ACK, ack=y+1 (+ request data)1 RTT of setup; TLS adds 1 more (TLS 1.3) before the HTTP request is protected
SYN, SYN-ACK, ACK: one full round trip before the client can send its request. The server holds a half-open entry between the second and third steps.
  1. 1

    SYN

    The client picks a random initial sequence number and sends a segment with the SYN flag, plus options such as maximum segment size and window scaling.
  2. 2

    SYN-ACK

    The server records a half-open connection, picks its own initial sequence number, and acknowledges the client's.
  3. 3

    ACK

    The client acknowledges the server's number. The connection is established; the client may send data with this segment.

Cost: one round trip before the first request byte, plus TLS (one more round trip with TLS 1.3, two with 1.2). On a 150 ms intercontinental path, a fresh HTTPS request waits about 300 to 450 ms before the server sees it. Reusing an existing connection skips all of that, which is why keep-alive, pooling and HTTP/2's single connection are such large wins.

Closing: four segments and TIME_WAIT

Each direction is closed independently. The side that finishes first sends FIN; the other acknowledges, may keep sending, and later sends its own FIN, which is acknowledged. The side that closed first then enters TIME_WAIT for twice the maximum segment lifetime (60 seconds on Linux), keeping the connection's four-tuple reserved so stray late packets from the old connection cannot be mistaken for a new one.

StateWhere it appearsWhy it matters
SYN_RECVServer, between SYN-ACK and ACKMany of these means slow clients or a SYN flood
ESTABLISHEDBoth sidesNormal open connections
CLOSE_WAITThe side that received FIN but has not closedAccumulating CLOSE_WAIT is an application bug: code never closes its sockets
TIME_WAITThe side that closed first, for ~60 sThousands are normal on busy clients; they consume ports toward the same destination

TIME_WAIT lands on whichever side closes first. When a client makes thousands of short connections to one server, its TIME_WAIT entries pin source ports for that destination, and it can run out: the same exhaustion pattern as NAT ports. The cure is connection reuse, not kernel tweaks that shorten safety timers.

Resets

A RST aborts a connection immediately, without the graceful exchange. It is sent when a packet arrives for a port with no listener ("connection refused"), when an application closes a socket with unread data, when a middlebox (load balancer, NAT, firewall) has lost or timed out its state for the connection, or when a process crashes. "Connection reset by peer" in logs means one of these happened on the other end or in between, most often an idle connection that a load balancer or NAT had already dropped.

SYN floods and SYN cookies

An attacker sends huge numbers of SYNs from spoofed addresses and never completes the handshake, filling the server's half-open table so real clients cannot connect. SYN cookies defend against it: when the backlog is full, the server encodes the connection details into its initial sequence number instead of storing state, and only reconstructs the connection if a valid ACK returns. Large providers also absorb floods at the edge before they reach servers.

Trade-offs

The handshake buys reliable sequence agreement and protection against stale packets at the cost of a round trip per connection; TIME_WAIT buys safety at the cost of ports on the closing side. Schemes to skip the round trip exist (TCP Fast Open, TLS 1.3 0-RTT, QUIC's 0-RTT resumption) but trade some replay safety for speed, so they are used only for idempotent requests. The robust answer is to open connections rarely and reuse them.

In an interview

Tie it to connection management: "Each new connection to the database costs a TCP and TLS handshake, around 2 ms in-region and much more cross-region, so the service keeps a pool; our edge proxy keeps warm connections to origin so user requests never pay the far handshake." And for operational signals: "Rising CLOSE_WAIT means our code leaks sockets; rising TIME_WAIT on the client means we are not reusing connections."

Check yourself

A service's host shows tens of thousands of sockets in CLOSE_WAIT, growing steadily, and eventually the process runs out of file descriptors. What does this indicate?

TCP handshake and teardown · Backplane