---
title: "TCP Three-Way Handshake Explained: SYN, SYN-ACK, ACK"
description: Learn how the TCP three-way handshake uses SYN, SYN-ACK, and ACK to establish a reliable connection.
---

[Content Delivery Network Blog](https://blog.blazingcdn.com/en-us)

# [TCP Three-Way Handshake Explained: SYN, SYN-ACK, ACK](https://blog.blazingcdn.com/en-us/tcp-three-way-handshake-explained-syn-syn-ack-ack)

 Written by [Vadym Borovskyi](https://blog.blazingcdn.com/en-us/author/blazingcdn) | Nov 3, 2026, 12:37:32 AM

The 3 way handshake is the SYN, SYN-ACK, ACK exchange that opens every TCP connection, and it costs one full round trip before the client can send a single application byte. At an 80 ms round-trip time (RTT), that is 80 ms of dead air per new connection. HTTPS adds TLS on top: TLS 1.2 costs two more round trips and TLS 1.3 costs one, so a cold HTTPS request needs three to four RTTs before the first response byte arrives.

Under RFC 9293 and RFC 8446, as of 2026, a new HTTPS connection over TCP and TLS 1.3 needs 3 round trips before the first response byte: 1 for the TCP handshake, 1 for TLS, and 1 for the request. At a 100 ms RTT that is 300 ms before any server processing time, which is why handshake cost is set by distance more than by bandwidth.

## **How the 3 way handshake works, packet by packet**

The TCP handshake synchronizes two things: initial sequence numbers in both directions, and the options each side will use for the life of the connection. Each side proves it can receive by acknowledging the other side's sequence number. One round trip is the minimum for that, because each side must see the other side's reply.

### Step 1: SYN

The client sends a segment with the SYN flag set and a 32-bit initial sequence number (ISN). Under RFC 6528 the ISN is generated from a keyed hash of the connection 4-tuple plus a clock, so off-path attackers cannot predict it. The SYN carries the options that matter later: Maximum Segment Size (MSS), the window scale factor, SACK-permitted, timestamps, and a TCP Fast Open cookie if one is cached. The SYN consumes one sequence number even though it carries no payload.

### Step 2: SYN-ACK

The server picks its own ISN and replies with SYN and ACK both set. The acknowledgment number is the client ISN plus one. On Linux the half-open connection now sits in the SYN queue, sized by net.ipv4.tcp\_max\_syn\_backlog. If that queue overflows and net.ipv4.tcp\_syncookies is enabled, the kernel encodes the connection state into the server ISN itself (a SYN cookie) and keeps no state at all. The cost is that some options, historically window scaling and SACK, survive only if timestamps are enabled to carry them.

### Step 3: ACK

The client acknowledges the server ISN plus one. The connection is now ESTABLISHED on the client, and it moves to ESTABLISHED on the server when this ACK arrives, at which point it enters the accept queue (bounded by the listen backlog and net.core.somaxconn, 4096 by default since Linux 5.4). The client may put request data in this same segment, which is why the SYN syn-ack ack sequence costs exactly 1 RTT of latency rather than 1.5.

## **Why does the TCP three way handshake add a round trip?**

The TCP three way handshake adds a round trip because the client cannot safely send data until the server has confirmed it received the client's sequence number and agreed on options. Without TCP Fast Open, application bytes leave the client only after the SYN-ACK returns, so every new connection pays one full RTT, whatever the bandwidth of the link.

That round trip compounds with everything layered above it. TLS 1.2 needs two more RTTs for a full handshake. TLS 1.3 needs one. The HTTP request and response need one more. Bandwidth does not shorten any of these, and slow start then holds the first flight of response data to the initial congestion window, 10 segments by default on Linux, or roughly 14 KB.

The real damage happens on the tail. Under RFC 6298 the initial retransmission timeout is 1 second, so a single lost SYN or SYN-ACK adds at least 1,000 ms to connection setup. Linux retries a SYN 6 times by default (net.ipv4.tcp\_syn\_retries), with backoff of 1, 2, 4, 8, 16 and 32 seconds, which is why connect timeouts cluster near 127 seconds on default kernels. If your p99 connect time has a bump just above 1 second, you are looking at handshake loss or a full queue, not slow routing.

## **Handshake cost by protocol stack: TLS 1.3, QUIC and TCP Fast Open**

The useful unit is round trips before the first response byte on a brand-new connection, multiplied by RTT. The table below counts the TCP handshake, the TLS or QUIC crypto handshake, and the request itself, and excludes server think time and DNS. These counts are protocol behavior per the relevant RFCs, so they hold as of 2026 regardless of vendor.

| Stack (new connection) | RTTs to first byte | At 20 ms RTT | At 80 ms RTT | At 150 ms RTT |
| --- | --- | --- | --- | --- |
| TCP plus TLS 1.2, full handshake | 4 | 80 ms | 320 ms | 600 ms |
| TCP plus TLS 1.3, full handshake | 3 | 60 ms | 240 ms | 450 ms |
| TCP plus TLS 1.3 with 0-RTT resumption | 2 | 40 ms | 160 ms | 300 ms |
| QUIC (HTTP/3), first visit | 2 | 40 ms | 160 ms | 300 ms |
| QUIC with 0-RTT, or TCP Fast Open plus TLS 1.3 0-RTT | 1 | 20 ms | 80 ms | 150 ms |

Cutting RTT from 150 ms to 20 ms saves more time on a plain TLS 1.3 stack (390 ms) than any protocol upgrade saves at a fixed 150 ms RTT (at most 300 ms).

### TLS 1.3: one round trip removed, and why 0-RTT is conditional

TLS 1.3 sends the key share in the ClientHello, so the server can answer with its key share, certificate and Finished in one flight. 0-RTT early data goes further on resumption, but early data is replayable by design under RFC 8446. Restrict it to idempotent GET requests and expect many servers to accept it only for safe methods.

### QUIC: transport and crypto in one handshake

QUIC (RFC 9000) runs the transport and TLS 1.3 handshakes together over UDP, so it saves the separate TCP round trip. It also avoids head-of-line blocking across streams and survives client IP changes through connection IDs. The trade-offs are UDP that some enterprise networks rate-limit or block, higher CPU cost per byte than kernel TCP with mature offloads, and the need for a TCP fallback path that you still have to tune.

### TCP Fast Open: correct on paper, fragile in the wild

TCP Fast Open (RFC 7413) lets a client that holds a server cookie send data in the SYN, removing the handshake round trip on repeat connections. Deployment stayed small because middleboxes drop or strip SYNs that carry data, and major browsers stopped enabling it by default. It is still worth enabling between infrastructure you control, such as edge to origin, where both ends and the path are known.

## **Why a CDN cuts the TCP handshake cost more than protocol tweaks**

Every row in the table multiplies by RTT, so the strongest lever is shortening the distance the handshake travels. A CDN terminates TCP and TLS at an edge close to the user, then reaches the origin over connections it already holds open. Those warm connections pay neither the 3 way handshake nor slow start again.

A worked example, using our own arithmetic: a user 150 ms from origin on TCP plus TLS 1.3 waits 3 x 150 = 450 ms before the first byte. Put an edge 20 ms from that user. A cache hit costs 3 x 20 = 60 ms. A cache miss costs 60 ms plus one 150 ms round trip from edge to origin over a pooled connection, so 210 ms. The miss is still 240 ms better than going direct, and at a 90% hit ratio the blended figure is about 75 ms.

The same logic explains why connection reuse matters as much as protocol choice. HTTP/2 multiplexing and long keepalive timeouts mean the handshake is paid once per client session instead of once per object. If your edge-to-origin pool churns, you pay the origin RTT handshake on misses again and most of the gain disappears.

For high-volume static delivery, an Anycast edge that terminates TLS 1.3 near the user captures most of this saving without needing QUIC. BlazingCDN runs an [**Anycast CDN with TLS 1.3, HTTP/2 and origin shield with request coalescing**](https://blazingcdn.com/anycast-cdn/), though it does not support HTTP/3 by design, so teams that need the QUIC row of the table should pair it with a provider that does.

## **How to tune the TCP handshake on Linux servers**

These settings matter on origins and on any self-run edge tier. Change one at a time and measure connect-time percentiles before and after.

1. Keep net.ipv4.tcp\_syncookies at 1. It costs nothing until the SYN queue overflows, and then it keeps the listener reachable during floods or traffic spikes.
2. Raise net.ipv4.tcp\_max\_syn\_backlog and net.core.somaxconn together, and set the application listen backlog to match. In nginx that is the backlog parameter on the listen directive, for example backlog=4096. The kernel silently caps the application value at somaxconn.
3. Set net.ipv4.tcp\_fastopen to 3 (client and server) on edge-to-origin paths you control, and add the fastopen parameter to the nginx listen directive, for example fastopen=256, which bounds the queue of pending Fast Open requests.
4. Set net.ipv4.tcp\_slow\_start\_after\_idle to 0 on servers with long-lived keepalive connections, so a reused connection does not collapse its congestion window after a pause.
5. Lower net.ipv4.tcp\_synack\_retries from its default of 5 to 2 or 3 on internet-facing listeners, which frees half-open slots faster under SYN pressure.

## **Trade-offs, failure modes and observability gaps**

SYN cookies keep you alive but degrade options when timestamps are off, which can quietly cap throughput on long fat paths. Larger backlogs hide an application that accepts too slowly: the queue absorbs the burst, then latency grows instead of errors appearing. Aggressive keepalive reuse lowers handshake count but holds file descriptors and memory, and load balancers with short idle timeouts will reset connections that clients still believe are open.

The observability gap is that most dashboards report request latency, not connect latency. A slow handshake looks identical to a slow backend in a p99 latency chart. The kernel counters that expose it (ListenOverflows, ListenDrops and SyncookiesSent in the TcpExt group reported by nstat) are rarely scraped by default.

### Verify this on your own stack

- In Resource Timing or Navigation Timing data from real users, chart connectEnd minus connectStart, and secureConnectionStart to connectEnd for the TLS share, split by country.
- Scrape TcpExtListenOverflows and TcpExtSyncookiesSent; any non-zero rate means the handshake is failing before your application sees it.
- Check the rtt field in socket statistics (ss with the info flag) on origin listeners to confirm the RTT you are multiplying by.
- Look for a connect-time cluster just above 1,000 ms, the signature of SYN retransmission.

## **Who should care about handshake cost, and who should not**

This matters most for workloads dominated by new connections over long distances: API clients that do not pool, mobile users who reconnect often, first page loads, and video players opening fresh connections to segment hosts. It also matters for origin teams whose CDN pools churn.

It matters least for long transfers on established connections. A 2 GB game patch over a single connection spends a few hundred milliseconds on handshakes and minutes on throughput, so congestion control, loss and cache hit ratio dominate there.

## **FAQ: TCP three way handshake, SYN, SYN-ACK, ACK**

### How long does a TCP 3 way handshake take?

A TCP 3 way handshake takes one round-trip time before the client can send data, so its cost equals the RTT between the two hosts. That is roughly 5 to 20 ms inside a metro area and 80 to 200 ms across continents. A lost SYN or SYN-ACK adds at least 1 second because of the initial retransmission timeout.

### Why is the TCP handshake three steps instead of two?

The TCP handshake needs three segments because each side must confirm the other received its initial sequence number. The SYN and SYN-ACK exchange both sequence numbers, and the final ACK confirms the server's. A two-step exchange would leave the server unable to tell a live client from a stale or spoofed SYN, which RFC 9293 explicitly guards against.

### Does QUIC remove the TCP three way handshake?

QUIC removes the TCP three way handshake entirely because it runs over UDP and combines transport setup with the TLS 1.3 handshake. A first QUIC connection needs one round trip before the request, versus two for TCP plus TLS 1.3. With 0-RTT resumption, QUIC can send an idempotent request in the very first flight.

### Can data be sent in the SYN SYN-ACK ACK exchange?

Data can ride in the final ACK of the SYN SYN-ACK ACK exchange on any normal TCP stack. Data inside the SYN itself requires TCP Fast Open and a cookie from a previous connection. Fast Open saves one round trip, but middleboxes often drop data-carrying SYNs, so it works best between servers you control.

### What causes TCP handshake timeouts on a busy server?

TCP handshake timeouts on busy servers usually come from a full SYN queue or accept queue, not from the network. When the application accepts connections too slowly, the kernel drops incoming ACKs or SYNs, clients retransmit after 1 second, and connect times jump. The ListenOverflows and ListenDrops counters confirm it.

## **Measure your handshake budget per region this week**

Pull a week of real-user timing data, compute connect plus TLS time at p50 and p99 per country, and multiply your measured RTT by the round-trip count for your stack from the table above. If the arithmetic predicts 240 ms and you observe 1,200 ms at p99, the gap is loss or queue overflow, and the kernel counters will say which. Then rerun the same numbers assuming an edge 20 ms from users and a 90% hit ratio, which tells you whether distance or protocol is your bigger lever.

If distance wins and your traffic is high-volume static content, the [**BlazingCDN performance metrics page**](https://blazingcdn.com/performance-metrics/) publishes the June 2026 regional measurements and a public test file you can time from your own users' networks.

[View full post](https://blog.blazingcdn.com/en-us/tcp-three-way-handshake-explained-syn-syn-ack-ack)

```json
{
  "@context" : "http://schema.org",
  "@type" : "BlogPosting",
  "author" : {
    "@type" : "Person",
    "name" : "Vadym Borovskyi"
  },
  "dateModified" : "2026-11-09T14:45:16.994Z",
  "datePublished" : "2026-11-03T00:37:32Z",
  "headline" : "TCP Three-Way Handshake Explained: SYN, SYN-ACK, ACK",
  "image" : {
    "@type" : "ImageObject",
    "height" : 768,
    "url" : "https://143144902.fs1.hubspotusercontent-eu1.net/hubfs/143144902/Gemini-Blog/image-Nov-03-2026-12-35-39-5806-AM.jpeg",
    "width" : 1376
  },
  "mainEntityOfPage" : "https://blog.blazingcdn.com/en-us/tcp-three-way-handshake-explained-syn-syn-ack-ack",
  "publisher" : {
    "@type" : "Organization",
    "logo" : {
      "@type" : "ImageObject",
      "height" : 60.0,
      "url" : "https://143144902.fs1.hubspotusercontent-eu1.net/hubfs/143144902/Logo%20b-3.png",
      "width" : 245.85367
    },
    "name" : "CDN Blog"
  }
}
```