dig NS example.com still lists the old provider. The A record still points at the old server too. The usual answer is "wait for propagation," but that tells you nothing about whether the change is on its way or never happened at all. dig +trace can tell the difference, because it walks the delegation chain itself instead of asking a cache.
This comes up constantly at the support desk, and the word "propagating" often gets used before anyone has looked at what the TLD is actually publishing. One trace usually settles whether you are dealing with a registrar problem, a cache problem, or a broken zone at the new provider.
What a plain dig is really telling you
dig NS example.com with no server specified, dig sends the question to whatever resolver your system is configured to use. On many Linux machines that is a local stub (for example 127.0.0.53 with systemd-resolved), which forwards to your ISP, your VPS provider, or a public resolver. The answer you see is whatever that resolver has cached. If the TTL in the answer is counting down between runs, you are looking at a cached copy, not a fresh lookup.
There is a second detail that trips people up. A domain actually has two NS sets:
- The parent side: the delegation records published in the TLD zone (for example
.com). This is what the registrar updates when you change nameservers. - The child side: the NS records at the apex of your own zone, served by your nameservers.
dig NS answer usually comes from the child side, from whichever servers the resolver currently believes are authoritative. Changing nameservers at the registrar only touches the parent side. If the resolver still trusts the old servers, and the old servers still serve your zone, they will happily keep answering with their own names.
Walking the delegation with dig +trace
dig +trace starts at the root. It uses your configured resolver only to get the list of root servers, then queries each level directly: a root server for the TLD referral, a TLD server for your domain's referral, and finally one of the nameservers that referral points to. Resolver caches do not influence the referrals you see.
BASH
# Follow the delegation from the root down to the final answer
dig +trace example.com
# Same walk, but ask for the NS set at the end
dig +trace NS example.comTEXT
# Illustrative output format (placeholder names and documentation IPs)
. 518400 IN NS a.root-servers.net.
;; Received 239 bytes from 127.0.0.53#53(127.0.0.53) in 0 ms
com. 172800 IN NS a.gtld-servers.net.
;; Received 1170 bytes from 192.0.2.1#53(a.root-servers.net) in 20 ms
example.com. 172800 IN NS ns1.new-provider.example.
example.com. 172800 IN NS ns2.new-provider.example.
;; Received 120 bytes from 192.0.2.30#53(a.gtld-servers.net) in 30 ms
example.com. 3600 IN A 198.51.100.20
;; Received 56 bytes from 203.0.113.53#53(ns1.new-provider.example) in 15 msexample.com. ... NS lines received from a.gtld-servers.net are the parent's view: the delegation the registry is publishing right now. The number next to them is the delegation TTL, which is how long a resolver may cache that referral. For .com and .net this is typically 172800 seconds, or two days. Other TLDs set their own values, so read it from your trace rather than assuming.
The last block shows which server gave the final answer. If it came from one of the new nameservers and the record is correct, the delegation and the new zone are both fine.
Two caveats. At each level, dig picks one server, so if a TLD is mid-update you could see different results on repeated runs. And +trace does not validate DNSSEC, so a clean trace does not rule out validation failures.
Reading the result: three common outcomes
+trace asked the TLD directly. The change has not reached the registry zone. Typical reasons include a change still pending at the registrar, a change that failed without an obvious error, a typo in a nameserver hostname, or a status lock on the domain such as clientUpdateProhibited or serverUpdateProhibited. Some registries also test the new nameservers before accepting them and reject the change if those servers do not answer authoritatively for the domain yet. Some ccTLDs publish updates on a schedule rather than immediately. Check the domain's status and nameserver fields with whois or an RDAP lookup, and check the registrar's change history. Waiting longer will not help here.
Outcome two: the TLD referral shows the new nameservers and the trace ends with the right answer, but your normal resolver still returns old data. Now it is caching. The resolver cached the old delegation or the old apex NS set, and it will keep using it until that TTL expires. Lowering record TTLs before the move does not shorten this, because the delegation TTL is set by the registry, not by you. The same logic about TTLs setting your real recovery time is covered in Thinking DNS Failover Is Instant, Until a Day-Long TTL Becomes Your Real RTO.
There is a stickier version of this. If the old provider still serves your zone with its own NS records at the apex, a resolver that asks the old servers gets an authoritative answer naming the old servers again. Depending on the resolver software, that child-side answer can take priority over the parent's referral, and the resolver may keep refreshing the old set for longer than you expect. The practical fix is on the old side: either update the records there to match the new zone, including changing its apex NS records to the new servers, or keep it serving identical data until well past the delegation TTL. Deleting the old zone immediately can also cause short failures for resolvers still holding the old delegation.
Outcome three: the TLD shows the new nameservers, but the final answer is wrong, or the new servers return REFUSED or SERVFAIL. The problem is the zone at the new provider. Common causes are a zone that was never created, a missing record, or an apex NS set copied from the old provider's export that still lists the old servers. If validating resolvers return SERVFAIL while non-validating ones work, look at DNSSEC, which is covered in Moved to Cloudflare Nameservers and Got SERVFAIL From a Stale DS Record.
Confirming each layer directly
+norec flag asks the server not to recurse, so you see only what it holds itself.
BASH
# Parent view: what the TLD publishes (look at the AUTHORITY section)
dig NS example.com @a.gtld-servers.net +norec
# Child view at the new provider: expect the 'aa' flag and the new NS set
dig NS example.com @ns1.new-provider.example +norec
# Child view at the old provider: is it still serving the old NS set?
dig NS example.com @ns1.old-provider.example +norec
# What a given resolver has cached, and the TTL left on it
dig NS example.com @1.1.1.1aa in the flags line. It means the server considers itself authoritative for the zone. If the old provider's server still shows aa with the old NS set, that is the server keeping the old delegation alive.
The last query is useful for estimating time. The TTL on a cached answer is roughly how long that resolver will keep serving it. Different public resolvers cache independently, so one can show the new set while another still shows the old one. Some public resolvers offer a cache purge tool; whether they do, and for which record types, is in their own documentation.
The practical order is simple. Run dig +trace first and look only at the referral from the TLD. If it is old, go to the registrar and the domain status, not the DNS host. If it is new, check what the old and new nameservers each say about the apex NS set, make them agree, and let the delegation TTL from your trace tell you how long the stragglers can last.