Type something to search...
How to diagnose slow DNS resolution?

How to diagnose slow DNS resolution?

To diagnose slow DNS resolution, first measure it: time a lookup with dig and read the Query time line, or use curl -w '%{time_namelookup}' to see how long name resolution takes inside a real request. Then narrow down where the delay comes from by comparing your usual resolver with a public one, repeating the query to see whether a cached answer is fast, tracing the delegation with dig +trace to time each authoritative server, and checking the client's own resolver configuration for timeouts, unreachable servers or slow IPv6 lookups. Each of those tests points at a different layer, so the combination tells you exactly what to fix.

A slow lookup is easy to miss because it hides in front of everything else. Your browser, API client or mail server waits for DNS before it can even open a connection, so a 2-second delay in resolution looks like a slow website or a sluggish app. In this guide you'll learn what "slow" actually means for DNS, a step-by-step method for finding the bottleneck, the commands to use on Linux, macOS and Windows, and the fixes for the most common causes.

What Counts as Slow?

It helps to know what normal looks like before you start measuring. Rough guidelines:

Lookup typeTypical timeWorth investigating
Answer from the local cache (OS or browser)Under 1 msRarely an issue
Answer cached at a nearby resolver1–30 msOver 50 ms consistently
Uncached lookup needing recursion20–200 msOver 300 ms consistently
Any lookup—Anything around 1, 2, 5 or 10 seconds

That last row matters most. Delays that land on round numbers such as 1, 2, 5 or 10 seconds are almost never "slowness". They're timeouts: something sent a query, got no reply, waited, and then retried with another server or another protocol. Finding which query timed out is usually the whole diagnosis.

Step 1: Measure the Delay

With dig

dig prints how long the query took at the bottom of its output:

dig www.example.com A
;; ANSWER SECTION:
www.example.com.        300     IN      A       192.0.2.80

;; Query time: 186 msec
;; SERVER: 192.168.1.1#53(192.168.1.1) (UDP)
;; WHEN: Sat Oct 18 16:02:11 BST 2026
;; MSG SIZE  rcvd: 60

The SERVER line tells you which resolver answered, and Query time is the time between sending the query and receiving the response. Run it again straight away:

dig www.example.com A | grep "Query time"
;; Query time: 4 msec

A big drop on the second run is normal. The first query was a cache miss that needed recursion, and the second came from the resolver's cache. If both runs are slow, the resolver itself or the path to it is the likely problem.

Note that dig talks to the DNS server directly. It doesn't use your operating system's cache, /etc/hosts, or the browser's cache, which makes it ideal for isolating the network side.

With curl

To see DNS time inside a real request, curl can print a timing breakdown:

curl -o /dev/null -s -w 'dns: %{time_namelookup}s  connect: %{time_connect}s  tls: %{time_appconnect}s  total: %{time_total}s\n' https://www.example.com/
dns: 2.014211s  connect: 2.031554s  tls: 2.078912s  total: 2.190344s

Here DNS took just over 2 seconds while everything after it was quick. That pattern, a delay sitting right on a round number, strongly suggests a timeout and retry. Unlike dig, curl uses the system resolver, so it reflects what applications on that machine actually experience.

On Windows With PowerShell

Clear-DnsClientCache
Measure-Command { Resolve-DnsName www.example.com -Type A -DnsOnly } |
  Select-Object TotalMilliseconds

-DnsOnly makes Resolve-DnsName use DNS only, skipping fallbacks such as LLMNR and NetBIOS. You can also add -Server 1.1.1.1 to compare a specific resolver.

Step 2: Is It the Resolver or Everything?

Next, compare your normal resolver with a couple of well-known public ones. Use a name that's unlikely to be cached, or run each a few times and compare the cached times:

for server in 192.168.1.1 1.1.1.1 8.8.8.8 9.9.9.9; do
  printf '%-14s' "$server"
  dig @"$server" www.example.com A +tries=1 +time=3 | awk '/Query time/ {print $4, $5}'
done
192.168.1.1   912 msec
1.1.1.1       14 msec
8.8.8.8       19 msec
9.9.9.9       17 msec

The results tell you where to look:

  • Only your usual resolver is slow: The problem is that resolver, such as an overloaded router, a struggling ISP resolver, or a corporate resolver with a slow upstream forwarder.
  • Every resolver is slow for one domain: The domain's authoritative nameservers are probably slow or partly unreachable. Go to Step 4.
  • Every resolver is slow for every domain: The network path itself is the issue, such as packet loss, a congested link, or a firewall interfering with DNS.

Check for Packet Loss

DNS usually travels over UDP, and a lost UDP packet isn't retransmitted by the network. The client simply waits for its timeout and tries again. Even a few percent loss can make lookups intermittently slow. Test the path to your resolver:

mtr -rwc 100 192.168.1.1

Look at the Loss% column. Any steady loss on the hop to the resolver, or on the resolver itself, explains periodic slow lookups.

Step 3: Check the Client's Resolver Configuration

If public resolvers are fast when queried directly but applications on the machine are still slow, the problem is often local configuration.

Linux With resolv.conf

On systems that use /etc/resolv.conf directly, the C library tries the listed nameservers in order. If the first one is unreachable, every lookup waits for the timeout (5 seconds by default) before trying the next.

cat /etc/resolv.conf
nameserver 10.0.0.53
nameserver 1.1.1.1
options timeout:5 attempts:2

If 10.0.0.53 has been decommissioned, every lookup on that machine starts with a 5-second wait. Test each listed server directly:

for ns in $(awk '/^nameserver/ {print $2}' /etc/resolv.conf); do
  echo "== $ns"
  dig @"$ns" www.example.com A +tries=1 +time=2 | grep -E 'Query time|timed out|no servers'
done

Remove dead servers. The options line accepts timeout:n, attempts:n and rotate, which can soften the impact while you fix the underlying problem, but they're not a substitute for removing a broken nameserver.

Linux With systemd-resolved

Many distributions run systemd-resolved, in which case /etc/resolv.conf points at the local stub 127.0.0.53. Use resolvectl to see the real upstream servers and to time lookups through the stub:

resolvectl status
resolvectl query www.example.com
www.example.com: 192.0.2.80                     -- link: eth0

-- Information acquired via protocol DNS in 1.9ms.
-- Data is authenticated: no; Data was acquired via local or encrypted transport: no
-- Data from: cache

The Data from line tells you whether the answer came from the cache or the network. resolvectl statistics shows cache hits and misses and DNSSEC verdicts, which helps you confirm the cache is actually being used.

macOS

macOS doesn't rely on /etc/resolv.conf for most applications. Check the resolvers it actually uses with:

scutil --dns | grep -E 'resolver|nameserver|domain'

Look for unexpected resolvers, such as ones left behind by a VPN client, and for per-domain resolvers that might point at a server that's no longer reachable.

Windows

Get-DnsClientServerAddress -AddressFamily IPv4,IPv6 |
  Where-Object ServerAddresses |
  Format-Table InterfaceAlias, AddressFamily, ServerAddresses

Windows queries the preferred server first and falls back to others on timeout, so a dead preferred server causes the same kind of delay as on Linux. Watch out for stale IPv6 DNS servers on an interface, which are easy to overlook.

Step 4: Time the Authoritative Servers

If the delay only affects certain domains, the resolver is probably waiting on that domain's authoritative nameservers. dig +trace walks the delegation from the root and prints the time taken at each step:

dig www.example.com A +trace
.                       518400  IN      NS      a.root-servers.net.
;; Received 811 bytes from 127.0.0.53#53(127.0.0.53) in 2 ms

com.                    172800  IN      NS      a.gtld-servers.net.
;; Received 1170 bytes from 198.41.0.4#53(a.root-servers.net) in 21 ms

example.com.            172800  IN      NS      ns1.example.net.
example.com.            172800  IN      NS      ns2.example.net.
;; Received 287 bytes from 192.5.6.30#53(a.gtld-servers.net) in 33 ms

www.example.com.        300     IN      A       192.0.2.80
;; Received 60 bytes from 198.51.100.53#53(ns2.example.net) in 1408 ms

The last hop took 1.4 seconds, so the delay is with the domain's own nameservers. Query each one individually to find the slow or broken one:

for ns in $(dig example.com NS +short); do
  printf '%-22s' "$ns"
  dig @"$ns" www.example.com A +norecurse +tries=1 +time=3 | awk '/Query time/ {print $4, $5} /timed out/ {print "TIMEOUT"}'
done
ns1.example.net.      24 msec
ns2.example.net.      TIMEOUT

A resolver that picks the dead server waits for it to time out before trying the other one. Good resolvers learn which servers are slow and avoid them, but the first lookups after a cache flush still suffer. The fix is to repair or remove the broken nameserver at your DNS provider and at the registrar.

Long CNAME Chains

Each CNAME in a chain can point into a different zone, and each zone may need its own lookups. Check how many hops a name takes:

dig www.example.com A +noall +answer
www.example.com.        300     IN      CNAME   www.example.com.cdn.example.net.
www.example.com.cdn.example.net. 60 IN  CNAME   edge.example.org.
edge.example.org.       20      IN      A       203.0.113.40

Three zones are involved, and two of the records have short TTLs, so uncached lookups will be slower than for a direct A record. That's not wrong, but if you control the chain it's worth keeping it short.

Step 5: Look for the Classic Timeout Causes

These are the most common causes behind lookups that take exactly a few seconds.

IPv6 (AAAA) Queries Being Dropped

Most clients ask for A and AAAA records in parallel. Some broken firewalls, home routers or middleboxes drop the second packet when both are sent from the same source port, so one reply never arrives and the client waits for its timeout. On Linux, the single-request-reopen option in resolv.conf works around this by using a fresh socket for the second query:

options single-request-reopen

Test the theory by comparing the two query types directly:

dig www.example.com A    | grep "Query time"
dig www.example.com AAAA | grep "Query time"

If AAAA lookups are consistently slow or time out while A lookups are fast, look at the firewall or resolver handling of AAAA queries.

Large Responses and TCP Fallback

Responses that don't fit in a UDP packet, often because of DNSSEC signatures or long TXT records, are truncated, and the client retries over TCP. If a firewall blocks TCP port 53, or drops IP fragments, the retry fails and lookups time out. Check the response size and whether TCP works:

dig example.com DNSKEY +dnssec | grep "MSG SIZE"
dig example.com DNSKEY +dnssec +tcp | grep -E "Query time|MSG SIZE"

If the +tcp query fails or hangs, allow TCP port 53 between your clients and resolvers, and between your resolvers and the internet.

Search Domains

A name without a trailing dot may be tried with each search domain appended first. With search corp.example.com example.com and the default ndots:1, a lookup for api is tried as api.corp.example.com and api.example.com. In containers, where ndots:5 is common, even api.example.net may be tried with several suffixes before the real name. Each failed attempt costs a round trip, and if a search domain's servers are slow, it costs a lot more. Use fully qualified names in configuration, or reduce the search list.

Reverse Lookups

Some services, such as SSH, mail servers and logging tools, perform a reverse DNS lookup on every connecting IP. If the PTR lookup times out, the connection appears slow even though forward DNS is fine. Test it:

dig -x 203.0.113.25 | grep -E "status|Query time"

For SSH, UseDNS no in sshd_config (the default on modern OpenSSH) avoids the reverse lookup entirely.

Step 6: Measure Over Time

A single test can miss intermittent problems. A small script that times repeated lookups gives you a clearer picture. This one uses dnspython:

#!/usr/bin/env python3
"""Time repeated DNS lookups against a resolver and summarise the results."""
import statistics
import sys
import time

import dns.exception
import dns.resolver

server = sys.argv[1]
name = sys.argv[2]
runs = int(sys.argv[3]) if len(sys.argv) > 3 else 50

resolver = dns.resolver.Resolver(configure=False)
resolver.nameservers = [server]
resolver.lifetime = 5.0

times, failures = [], 0
for _ in range(runs):
    start = time.perf_counter()
    try:
        resolver.resolve(name, "A")
        times.append((time.perf_counter() - start) * 1000)
    except dns.exception.DNSException:
        failures += 1
    time.sleep(0.2)

if times:
    times.sort()
    p95 = times[int(len(times) * 0.95) - 1] if len(times) >= 20 else max(times)
    print(f"runs={runs} ok={len(times)} failed={failures}")
    print(f"median={statistics.median(times):.1f} ms  p95={p95:.1f} ms  max={max(times):.1f} ms")
else:
    print(f"All {runs} lookups failed")
pip install dnspython
python3 dns_timing.py 192.168.1.1 www.example.com 100
runs=100 ok=99 failed=1
median=3.8 ms  p95=41.2 ms  max=2004.6 ms

The median looks healthy, but the maximum lands on 2 seconds and one query failed outright. That's the signature of occasional packet loss or an overloaded resolver, and it explains why users complain about "random" slowness. For heavier testing of resolvers you run yourself, DNS-OARC's dnsperf and resperf tools are designed for load testing.

Fixing the Most Common Causes

Once you've found the layer at fault, the fixes are usually straightforward:

  1. Remove dead or distant resolvers from DHCP, resolv.conf, VPN profiles and network settings.
  2. Use a nearby, reliable resolver, either a well-run local caching resolver or a public resolver with good coverage in your region.
  3. Run a local cache on busy servers, such as systemd-resolved, Unbound or dnsmasq, so repeated lookups don't leave the machine.
  4. Fix broken authoritative servers for your own domains, and make sure every nameserver listed at the registrar actually answers.
  5. Allow TCP port 53 and EDNS through firewalls so large responses don't fail.
  6. Keep CNAME chains short and avoid very low TTLs unless you need them.
  7. Use fully qualified names in application configuration to avoid search domain expansion.

If you run Unbound as a caching resolver, these options help keep popular names warm and answers fast:

server:
    prefetch: yes
    serve-expired: yes
    serve-expired-ttl: 86400
    msg-cache-size: 64m
    rrset-cache-size: 128m

prefetch refreshes popular records shortly before they expire, and serve-expired lets Unbound answer from a recently expired cache entry while it fetches a fresh one, which hides slow upstream servers from clients.


FAQ: Slow DNS Resolution

Run dig with the name you want to test and read the Query time line near the bottom of the output. To see the DNS time inside a real web request, use curl with the time_namelookup write-out variable.

The first lookup is usually a cache miss, so the resolver has to contact root, TLD and authoritative servers. The second answer comes straight from the resolver's cache, which is far faster.

Five seconds is the default resolver timeout on Linux. A lookup that takes exactly that long usually means the first nameserver in your configuration isn't responding, or one of the parallel A and AAAA queries was dropped.

It can if your current resolver is slow, overloaded or far away. Measure first by comparing query times against your current resolver and a few public ones, because a good local resolver is often just as fast.

It adds some overhead for validation and larger responses, but on a healthy network the difference is small. Problems usually appear only when large responses are blocked or fragmented and the client has to fall back to TCP.

Containers often inherit a long search domain list or a high ndots setting, so each name is tried with several suffixes first. Use fully qualified names with a trailing dot, or lower ndots, and check which resolver the container is using.

Query the same name against several resolvers. If only your resolver is slow, the problem is local. If every resolver is slow for that one domain, use dig +trace and query each of its nameservers directly to find the slow one.


Conclusion

Slow DNS resolution is rarely mysterious once you measure it. Start with dig and curl to put a number on the delay, then compare resolvers to separate a slow local resolver from slow authoritative servers or a bad network path. Delays on round numbers point to timeouts, and timeouts point to a specific server, protocol or packet that isn't getting a reply.

Most fixes are simple: remove dead resolvers, allow TCP and large responses through the firewall, repair broken nameservers, and keep a cache close to your clients. Run a timing script for a while after making changes, so you can confirm that the slow outliers have gone and not just the average.

Tags :
Share :

Related Posts

What is the difference between an A record and a CNAME record?

What is the difference between an A record and a CNAME record?

The difference between an A record and a CNAME record is what they point to. An A record points a hostname directly at an IPv4 address, such

Dive Deeper
What are the best DNS providers for websites?

What are the best DNS providers for websites?

The best DNS providers for most websites are Cloudflare for a fast, free, easy starting point, Amazon Route 53 if you already run on AWS, **G

Dive Deeper
What are the best public DNS resolvers?

What are the best public DNS resolvers?

The best public DNS resolvers for most people are Cloudflare (1.1.1.1) for speed and privacy, Google Public DNS (8.8.8.8) for reliability and

Dive Deeper