Aller au contenu principal

Guides / fix

How to fix a slow DNS lookup

A slow DNS lookup is time spent before the connection to a site even begins, and it is almost always fixable by changing which resolver you ask. The page has not started loading yet. Your device is still waiting to learn where to send the request.

What a slow lookup is measuring

Loading a page starts with a name lookup, then a TCP connection, then a TLS handshake, then the server's own thinking time. Only the first of those is DNS, and it is the only one you can often improve without touching the site at all.

Two numbers get confused here. A cached lookup costs almost nothing, because the answer is already on your machine or one hop away. A cold lookup can involve a query to the root, another to the top level domain, and another to the domain's own nameservers, each a round trip across whatever distance separates you from those servers. Under 20 ms warm and under 100 ms cold are unremarkable. Anything approaching a second means one of the hops is far away, overloaded, or timing out and being retried.

Modern pages make this worse by having many hostnames. Fonts, analytics, images and payment widgets each need their own lookup, and a browser that resolves ten hostnames at 300 ms apiece has spent three seconds on DNS before rendering anything useful.

Confirm DNS is the slow part

Measure before changing anything. The cleanest single command splits a request into its phases:

curl -o /dev/null -s -w "dns:%{time_namelookup} connect:%{time_connect} tls:%{time_appconnect} ttfb:%{time_starttransfer} total:%{time_total}\n" https://example.com

If time_namelookup is a small fraction of the total, DNS is not your problem and you should be reading about server response time instead. If it is a third or more, keep going. For the lookup on its own, dig prints the elapsed time for you:

dig example.com | grep "Query time"
dig @1.1.1.1 example.com | grep "Query time"
dig @8.8.8.8 example.com | grep "Query time"

On Windows, PowerShell gives the same reading:

Measure-Command { Resolve-DnsName www.example.com }
Measure-Command { Resolve-DnsName www.example.com -Server 1.1.1.1 }

Compare your default against the public resolvers. A big gap tells you the fix is on your side. Similar times everywhere point at the domain's own nameservers.

One result rules this guide out entirely. If a resolver answers instantly with NXDOMAIN, the name is not published and you are looking at a different problem, described in DNS_PROBE_FINISHED_NXDOMAIN.

Why it happens

  • A distant resolver. Public services run anycast, so the same address answers from a nearby location. An ISP resolver or a single office server does not, and every query pays the full round trip.
  • The first server in the list is dead. The client waits out its timeout, then asks the second. On glibc systems the default is 5 seconds before the first retry, which is exactly the pause people describe as "it hangs, then loads".
  • Very low TTLs. A 30 or 60 second TTL means almost every visitor pays for a fresh lookup, because the cached copy has already expired.
  • Long CNAME chains. Each link is another lookup. Chains of three or four are common behind CDNs and marketing tools.
  • Slow authoritative nameservers. A DNS provider with few locations answers quickly for some of the world and slowly for the rest.
  • DNSSEC validation. Validating a chain adds queries. It is normally cheap, but a partly broken chain causes retries that look like slowness.
  • Search domains. A resolver configured with suffixes tries example.com.corp.local before example.com, spending a failed query on each suffix first.
  • AAAA lookups with no IPv6. The system asks for both record types and waits for the answer it cannot use.
  • A VPN or filtering proxy sending every query through a tunnel to a resolver on another continent.
  • A router acting as forwarder with a tiny cache and an underpowered CPU.

How to fix it

On your device

  1. Clear the caches so your measurements are honest: ipconfig /flushdns on Windows, sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder on macOS, sudo resolvectl flush-caches on Linux.
  2. Look at which servers are configured and in what order: Get-DnsClientServerAddress, scutil --dns, or resolvectl status. Remove any entry that no longer answers, since a dead first entry costs you the timeout on every cold lookup.
  3. On Linux, shorten the wait while you investigate by adding options timeout:2 attempts:2 to /etc/resolv.conf, and trim unused search suffixes.
  4. Disconnect the VPN and measure again. If the number halves, the tunnel is the cause and its resolver setting is what to change.

On your network

  1. Set the resolver in DHCP on the router rather than device by device, so every client gets the same fast pair.
  2. Give the router's own forwarder a public resolver upstream instead of the ISP default, or bypass the forwarder entirely by handing clients the public addresses directly.
  3. On a business network with its own DNS server, check that it forwards rather than doing full recursion from a single site, and that its cache is large enough to survive the working day.

On your own domain

  1. Raise TTLs on records that rarely change. Five minutes is a reasonable floor for a record you might need to move quickly; an hour or a day suits everything stable.
  2. Flatten CNAME chains where you can. Point the record at the final target instead of a chain of aliases: dig www.example.com CNAME +short shows how deep yours goes.
  3. Use a DNS provider with anycast nameservers, and keep at least two nameservers on separate networks.
  4. Check that DNSSEC validates. Compare a normal query with one that skips validation: dig example.com @1.1.1.1 against dig +cd example.com @1.1.1.1. A large difference, or a SERVFAIL on the first only, means the chain is broken.

Check it from outside

Your own timings describe one network at one moment, which is the least useful sample you can take. A resolver that is 8 ms from you may be 400 ms from a customer in another region, and that customer is the one complaining.

Start by measuring the authoritative servers directly, which removes every cache between you and the source:

dig NS example.com +short
dig @ns1.example-dns.net example.com | grep "Query time"
dig example.com +trace

The +trace output walks the delegation one step at a time, so a hop that stalls is visible rather than averaged away. Then run the DNS query check, which resolves the name from checkpoints in different countries and reports each one separately. That is the measurement you cannot take from a laptop: it shows whether your nameservers are slow everywhere, which points at the provider, or slow from one continent, which points at their network footprint. If some locations return a different answer rather than a slower one, the question is propagation instead, covered in how to check DNS propagation.

Latency that drifts instead of breaking

DNS latency rarely breaks in an obvious way. It drifts, a nameserver loses a location, a TTL gets lowered during a migration and never raised again, and six weeks later the site feels sluggish for reasons nobody can point at. A single measurement cannot show a trend, which is why lookup time is worth recording on a schedule from the regions your visitors are in. HostTracker has been monitoring websites since 2004 and now watches over 500,000 websites from checkpoints in 158 cities, keeping the history that makes a slow drift visible. The other guides here are in the fix cluster, and the failure case where nothing comes back at all is DNS server not responding.

Check it now

Run the free check against your own site - no account needed.

Dns query

Monitor this permanently

Get alerted the moment it breaks: HostTracker checks from 300+ locations and notifies you by email, SMS, Slack, Telegram and more.

HostTracker features