Why a cached answer can mislead you
When a DNS update doesn't take effect, you typically have two possibilities: your authoritative nameserver holds the wrong record, or an old record is still being served from a cache and you simply need to wait for it to expire. To distinguish between those two cases, you need to query the authoritative nameserver directly and check what it actually has.
Finding that authoritative nameserver sounds straightforward, but a lot of the common advice floating around can hand you a stale or misleading answer. The reliable method is to walk the delegation chain from the root down, which is exactly what happens behind the scenes when any resolver processes your query.
The fast route: dig +short ns
If you haven't touched your authoritative DNS configuration in roughly a week, the quickest check is dig +short ns DOMAIN.
$ dig +short ns jvns.ca
art.ns.cloudflare.com.
roxy.ns.cloudflare.com.
That gives the right result here, and for most settled domains it will be fine. The danger appears right after you change nameservers — the response can be a cached record from before the change, so you can't trust it during a migration.
The reliable two-step walk
To get an answer that is always current, start at a root server and follow the referrals. We'll use jvns.ca as the example domain.
First, query one of the 13 root nameservers — say, h.root-servers.net — using dig @h.root-servers.net jvns.ca.
$ dig @h.root-servers.net jvns.ca
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 42165
;; flags: qr rd; QUERY: 1, ANSWER: 0, AUTHORITY: 4, ADDITIONAL: 9
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;jvns.ca. IN A
;; AUTHORITY SECTION: <------------ this is the section we're interested in
ca. 172800 IN NS c.ca-servers.ca. <------- we'll use this record
ca. 172800 IN NS j.ca-servers.ca.
ca. 172800 IN NS x.ca-servers.ca.
ca. 172800 IN NS any.ca-servers.ca.
;; ADDITIONAL SECTION:
c.ca-servers.ca. 172800 IN A 185.159.196.2
j.ca-servers.ca. 172800 IN A 198.182.167.1
x.ca-servers.ca. 172800 IN A 199.253.250.68
any.ca-servers.ca. 172800 IN A 199.4.144.2
c.ca-servers.ca. 172800 IN AAAA 2620:10a:8053::2
j.ca-servers.ca. 172800 IN AAAA 2001:500:83::1
x.ca-servers.ca. 172800 IN AAAA 2620:10a:80ba::68
any.ca-servers.ca. 172800 IN AAAA 2001:500:a7::2
;; Query time: 96 msec
;; SERVER: 198.97.190.53#53(198.97.190.53)
;; WHEN: Tue Jan 11 08:30:57 EST 2022
;; MSG SIZE rcvd: 289
The relevant output lives in the AUTHORITY SECTION:
ca. 172800 IN NS c.ca-servers.ca.
Any server listed there works; for this domain, that means the next hop is c.ca-servers.ca.. If you're querying a well-known TLD often enough, you can skip the root query and go straight to the TLD's nameservers, but starting at the root is the general approach.
Next, query that server with dig @c.ca-servers.ca jvns.ca.
$ dig @c.ca-servers.ca jvns.ca
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 24920
;; flags: qr rd; QUERY: 1, ANSWER: 0, AUTHORITY: 2, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;jvns.ca. IN A
;; AUTHORITY SECTION: <------------ this is the section we're interested in
jvns.ca. 86400 IN NS art.ns.cloudflare.com. <---- we'll use this record
jvns.ca. 86400 IN NS roxy.ns.cloudflare.com.
;; Query time: 26 msec
;; SERVER: 185.159.196.2#53(185.159.196.2)
;; WHEN: Tue Jan 11 08:32:44 EST 2022
;; MSG SIZE rcvd: 90
Again, look at the AUTHORITY SECTION:
jvns.ca. 86400 IN NS art.ns.cloudflare.com.
The result here is art.ns.cloudflare.com., which is the actual authoritative nameserver for jvns.ca. You can now query it directly to see the records it holds:
$ dig @art.ns.cloudflare.com. jvns.ca
jvns.ca. 292 IN A 172.64.80.1
This works reliably because it uses exactly the same source of truth that a real recursive resolver consults — the TLD nameserver that got the referral from the root. There is no cache in the path to inject an old record.
This method is particularly handy during a nameserver change at your registrar. Registrars don't propagate that change instantly; it can take roughly an hour. Walking the delegation chain this way shows you whether the registrar has actually published the new nameservers yet.
Other tools and why they can be wrong
A few other commands often get recommended for this job. Each has a caveat:
dig +trace jvns.caperforms the same root-to-TLD walk internally, so it's always accurate. The output is just noisier and harder to parse at a glance.dig ns jvns.causually works, but has two failure modes. The first is a cached response. The second is subtler: the answer comes from the authoritative nameserver itself (here,art.ns.cloudflare.com) rather than from the TLD server that issued the delegation. Normally those match, but in edge cases they may not.dig soa jvns.caexposes nameservers inside the SOA record.
$ dig SOA jvns.ca
jvns.ca. 3600 IN SOA art.ns.cloudflare.com. dns.cloudflare.com. 2267173366 10000 2400 604800 3600
^^^^^^^^^^^^^^^^^^^^^
here it is
whois jvns.careturns registry data, which can be cached and lag behind actual changes. On this domain it happens to be current:
$ whois jvns.ca | grep 'Name Server'
Name Server: art.ns.cloudflare.com
Name Server: roxy.ns.cloudflare.com
The SOA and whois approaches share the same fundamental weakness: they're one step removed from the delegation data held by the TLD server. If you're mid-migration, your resolver might still route to the old authoritative server, or the record you're reading simply hasn't been updated yet. Walking the chain from the root avoids both problems by always asking the server that owns the current delegation.



