Verifying DNS Propagation with dig Across Resolvers

Problem Statement

You have flipped the A record at the registrar or DNS provider and now need hard evidence that the change has reached real resolvers before declaring the cutover complete. Browser tests lie because of OS, browser, and local resolver caching, so you need authoritative confirmation from multiple independent public resolvers. This page is part of DNS Propagation Tracking and shows how to use dig to compare what each resolver currently serves and how long stale answers will persist.

Resolver query paths for dig verification A dig client queries the authoritative nameserver directly and two public recursive resolvers, comparing returned records and TTLs. dig Verification Across Resolvers dig client Authoritative NS Google 8.8.8.8 Cloudflare 1.1.1.1 Compare your terminal source of truth recursive cache recursive cache records + TTL
Query the authoritative server and each public resolver in turn, then compare the records and TTLs they return.

When to Use This Approach

  • You have just changed an A, AAAA, or CNAME record and need to confirm resolvers are serving the new value.
  • Users report intermittent access — some see the new origin, some the old — and you suspect partial propagation.
  • You lowered TTL ahead of the move (see How to Lower DNS TTL Before Migration) and want to confirm the short TTL is actually in effect.
  • You need a scriptable, dependency-free check that runs from any Unix host without relying on third-party web tools.
  • You must verify the authoritative answer matches what recursive resolvers cache before signing off the cutover.

Step-by-Step Instructions

1. Query the Authoritative Nameserver Directly

The authoritative nameserver is the source of truth — it answers with the record exactly as published, ignoring all recursive caches. Find the nameservers first, then query one of them by name so you are testing the real publication, not a cached copy.

# List the authoritative nameservers for the zone
dig example.com NS +short

# Query the new A record straight from an authoritative server (no recursion)
dig @ns1.example-dns.net example.com A +noall +answer

2. Query Public Recursive Resolvers

Recursive resolvers (8.8.8.8, 1.1.1.1) are what most users actually hit, and they cache answers for the duration of the record TTL. Query each one explicitly to see whether they still hold a stale answer or have picked up the new value.

# Google Public DNS — what a large slice of users resolve through
dig @8.8.8.8 example.com A +noall +answer

# Cloudflare 1.1.1.1 — second independent recursive view
dig @1.1.1.1 example.com A +noall +answer

# Quad9 for a third data point
dig @9.9.9.9 example.com A +noall +answer

3. Read the TTL Countdown to Predict Cache Expiry

The TTL value in a recursive resolver’s answer counts down toward zero on each subsequent query. A decreasing TTL means the resolver is serving a cached copy; when it hits zero it will re-fetch from authoritative. Poll the same resolver twice to see the countdown.

# First poll — note the TTL (second column)
dig @8.8.8.8 example.com A +noall +answer
# example.com.   286   IN   A   203.0.113.10

# Wait, poll again — TTL has dropped, confirming a cached (not fresh) answer
dig @8.8.8.8 example.com A +noall +answer
# example.com.   241   IN   A   203.0.113.10

4. Trace the Full Delegation Path

dig +trace walks the resolution chain from the root servers down through the TLD to the authoritative nameservers, bypassing recursive caches entirely. Use it when a resolver returns an unexpected answer and you need to confirm where in the delegation the wrong value originates.

# Walk root -> TLD -> authoritative, printing each delegation hop
dig +trace example.com A

# Restrict noise to just the final answer section while tracing
dig +trace +nodnssec example.com A

5. Confirm Old and New Origins Are Distinguishable

Before declaring success, prove you are reading the new IP and not a coincidental match. Compare the returned address against your known old and new origin IPs across every resolver, and only sign off once all recursive resolvers agree with authoritative.

# Loop the key resolvers and print each verdict in one pass
for r in 8.8.8.8 1.1.1.1 9.9.9.9; do
  echo -n "$r -> "; dig @$r example.com A +short
done

Those five commands are not interchangeable, and knowing which one answers which question is most of the skill. Each queries a different point in the resolution chain, so a disagreement between two of them is information rather than a contradiction.

Where each dig invocation reads from in the resolution chain A stub resolver, a public recursive resolver, and the authoritative nameserver shown as three points in the chain, with the dig command that reads each one and the question that command actually answers. Three caches, three commands, three questions Your OS / browser its own cache, own rules Recursive resolver caches for the record TTL Authoritative NS the published truth resolvectl flush-caches "why does my browser still show the old site?" dig @8.8.8.8 "what do real users get right now?" dig @ns1… / +trace "did my change actually publish?" Authoritative correct plus resolver stale is normal propagation. Authoritative wrong is a publishing bug. Only the middle column tells you anything about your users.
Start at the right-hand column: if the authoritative answer is wrong, nothing downstream is worth investigating yet.

Worked Example

A move shifts example.com from a legacy origin at 198.51.100.20 to a new load balancer at 203.0.113.10. TTL was lowered to 300 seconds the day before.

Immediately after publishing the change, authoritative is correct but Google still serves the old value:

# Authoritative — already correct
$ dig @ns1.example-dns.net example.com A +noall +answer
example.com.   300   IN   A   203.0.113.10

# Google 8.8.8.8 — still cached on the old origin, TTL counting down
$ dig @8.8.8.8 example.com A +noall +answer
example.com.   122   IN   A   198.51.100.20

Roughly two minutes later, after the cached TTL expires, the recursive resolvers re-fetch and converge:

$ for r in 8.8.8.8 1.1.1.1 9.9.9.9; do echo -n "$r -> "; dig @$r example.com A +short; done
8.8.8.8 -> 203.0.113.10
1.1.1.1 -> 203.0.113.10
9.9.9.9 -> 203.0.113.10

All three recursive resolvers now match authoritative on 203.0.113.10, so this resolver set has fully propagated. Continued global confirmation belongs to Monitoring Global DNS Propagation During Cutover.

Reading the countdown is what turns a snapshot into a prediction. Because the TTL field decrements on each query against the same resolver, two polls a few seconds apart tell you not just whether the answer is cached but exactly how much longer the stale value will survive — which is the number you need in order to say when, rather than whether, that resolver will converge.

Reading the TTL countdown to predict when a resolver will converge Successive dig polls against one resolver show the cached TTL falling from 286 to 122 to 0, at which point the resolver re-fetches and returns the new origin address instead of the legacy one. The second column is a countdown, not a setting Answer served by 8.8.8.8 TTL reported on each poll 198.51.100.20 — legacy origin, from cache 203.0.113.10 286 241 122 0 re-fetch → 300 A TTL that decrements proves you are reading a cache and tells you when it lapses. A TTL that never changes between polls means the resolver is enforcing its own floor and will not converge on your schedule.
Poll the same resolver twice before concluding anything: the delta between the two readings is the whole diagnosis.

Script the pass condition rather than eyeballing it. A loop that prints addresses is fine while you are investigating and unreliable as a sign-off, because the thing you are checking for is the absence of an unexpected value — an extra A record left behind, a second address from a load-balanced set, an old AAAA — and absence is exactly what the eye skips over. Compare against an explicit expected set and fail on anything outside it.

Verification

# Pass condition: every resolver returns ONLY the new IP and nothing else
dig @8.8.8.8 example.com A +short | grep -qx '203.0.113.10' && echo "google OK"

# Confirm no stale AAAA record lingers if you also moved IPv6
dig @1.1.1.1 example.com AAAA +short

A clean result is every recursive resolver returning exclusively the new origin IP, with a TTL no larger than your lowered value, and dig +trace ending at the correct authoritative nameservers.

FAQ

Why does my browser still load the old site when dig already shows the new IP? Browsers and operating systems keep their own DNS caches separate from public resolvers, and many hold answers for the OS-level minimum rather than the record TTL. Flush the OS resolver cache or test from an incognito session on a different network to confirm — dig against the public resolvers is the authoritative signal, not the browser.

What does the number after the record name in dig output mean? That is the remaining TTL in seconds for the cached answer at the resolver you queried. It counts down on each query against that resolver and, once it reaches zero, the resolver discards the entry and re-fetches from authoritative, which is exactly the moment propagation completes for that resolver.

Why does dig +trace sometimes disagree with dig @8.8.8.8? +trace resolves fresh from the root and ignores recursive caches, so it reflects the current published record, while @8.8.8.8 reflects whatever Google has cached until its TTL expires. A disagreement simply means 8.8.8.8 is still serving a cached answer that has not yet timed out.

Is querying 8.8.8.8 from one machine enough to represent Google’s resolvers? No. 8.8.8.8 is an anycast address served by many independent nodes worldwide, and each maintains its own cache, so the answer you get depends on which node your packets reached. A colleague on another continent querying the same address may legitimately get a different result for several minutes. That is why the parent DNS Propagation Tracking runbook samples from multiple regions rather than treating one query per provider as a verdict.

Why does dig sometimes return the right answer while curl still hits the old server? Because they may not be resolving the same way. dig speaks directly to whichever resolver you point it at, while curl goes through the system resolver, which on modern Linux is often a local caching stub with its own entry. Add --resolve to pin curl to a specific address when you want to test the origin rather than the resolution path, and flush the stub cache when you want the two tools to agree.

Should I check AAAA records even if the site is IPv4-only today? Yes, and specifically to confirm the absence of a stale one. A leftover AAAA record pointing at a decommissioned address is worse than no record at all, because dual-stack clients prefer IPv6 and will try it first, waiting for a timeout before falling back. The symptom is a site that feels inexplicably slow for a subset of users while every IPv4 check passes cleanly.

Related

← Back to DNS Propagation Tracking