API Latency Breakdown: DNS, TCP, TLS and Server Time

"The API is slow" is not one problem. A request spends its time in four places, each owned by someone different — and the first question in any latency incident is which one moved.

The four phases

  1. DNS lookup — turning the hostname into an address. Owned by your DNS provider and the client's resolver. Usually a few milliseconds when cached; tens or hundreds when the record's TTL has expired or the authoritative servers are slow.
  2. TCP connect — the handshake with the address DNS returned. It costs one round trip, so it is a direct reading of network distance: a few milliseconds within a region, 70–150 ms across an ocean.
  3. TLS handshake — certificate exchange and key agreement for HTTPS. One more round trip with TLS 1.3, two with 1.2, plus whatever the terminating server spends on cryptography. Owned by whoever terminates TLS: a load balancer, an API gateway, a CDN edge.
  4. Server wait — from the request being sent to the first byte of the response. This is your application (or the function, or the upstream it calls) doing the work. Cold starts of serverless functions land here.

Add them up and you have time to first byte. A request that reuses an open connection skips the first three entirely — which is why a "warm" benchmark from your laptop can look nothing like a customer's first request.

Reading a breakdown

  • Server wait grew, everything else flat — the application, its database or an upstream dependency. Not the network, not the cloud provider's edge.
  • TCP connect grew — the path got longer: traffic is being routed to a farther region, or across a congested link. Check where the address now points.
  • TLS grew, TCP did not — the terminating server is struggling (CPU, certificate chain size, OCSP), or a configuration change downgraded the protocol version.
  • DNS spikes on a schedule — a short TTL meeting slow authoritative servers; every expiry costs a full lookup.

Measuring it

From a terminal, curl reports the cumulative points:

curl -o /dev/null -s -w 'dns %{time_namelookup}  tcp %{time_connect}  tls %{time_appconnect}  ttfb %{time_starttransfer}\n' https://api.example.com/health

Each value is measured from the start, so subtract the previous one to get a phase. Run it a few times: the first run includes a cold DNS lookup, later ones may not.

For monitoring, the same split needs to be recorded on every scheduled check and kept, so a regression in one phase shows up against its own history instead of disappearing inside a total that "only" grew by 20%.

Frequently Asked Questions

Why is my TLS handshake slower than my TCP connect?

TLS needs at least one more round trip than TCP (TLS 1.3) or two (TLS 1.2), plus certificate verification and key agreement. Roughly one to two times the TCP connect time is normal; much more points at the terminating server or a large certificate chain.

What is a cold start, and where does it show up?

A serverless function that has not run recently must be started before it can answer. That time is spent after the request arrives, so it appears as server wait — not as DNS, TCP or TLS.

Why does a reused connection show no DNS, TCP or TLS time?

Because none happened: an open keep-alive connection skips all three. A monitor should record those phases as absent for that request, not as zero, or it will report impossibly fast lookups.

Does a CDN change the breakdown?

Yes. TCP and TLS terminate at the nearby edge, so both shrink. Server wait then includes the edge's cache lookup and, on a miss, the whole trip to your origin.

Stop checking this by hand

NetTests runs this kind of check on a schedule, stores historical results, and alerts your team the moment something changes.

Start monitoring free →
No credit card required  ·  Free plan available