DNS Troubleshooting: Records, TTL, DNSSEC & Email [2026]

Short answer: nearly every DNS incident collapses into five questions, and they should be asked in this order. Is the record actually present at the authoritative nameservers? Is a stale copy still cached because of a TTL you set last week? Is delegation pointing at the nameservers you think it is? Is DNSSEC validation failing? And if the symptom is email, is SPF/DKIM/DMARC misaligned rather than missing? Answer those with dig, working from the authoritative server outwards, and most outages are diagnosed in under ten minutes.

By Marcus Hale, Principal Infrastructure Engineer. Fourteen years operating authoritative DNS and mail authentication: self-hosted BIND and Knot zones, plus managed estates on Cloudflare, Route 53 and NS1, currently covering 40+ production domains. Full credentials, conference talks and contact details are on the author profile. Every protocol claim below is tied to the relevant RFC or vendor documentation and linked in place; every command output is real terminal output from a lab zone, with addresses replaced by RFC 5737 documentation ranges. Last reviewed 15 September 2026.

The 60-Second DNS Triage Ladder

Before theorising, run the query. The sequence below is what we actually work through on an incident call: it maps a symptom to the single command that most often identifies the cause.

Symptom First command Usual cause
Works for you, broken for a colleague dig @1.1.1.1 example.com A then dig @8.8.8.8 example.com A One resolver still holds a pre-change answer; its TTL has not expired
NXDOMAIN everywhere dig +trace example.com Record genuinely absent, or delegation broken at the parent
SERVFAIL on public resolvers, NOERROR direct from authoritative dig +cd example.com A DNSSEC validation failure (expired RRSIG or stale DS)
New record invisible hours later dig @ns1.yourprovider.net example.com A You edited a zone at a provider the domain is no longer delegated to
Mail rejected or landing in spam dig TXT _dmarc.example.com and dig TXT example.com DMARC alignment failure, or an SPF record over the lookup limit
Certificate renewal fails at issuance dig CAA example.com A CAA record that no longer lists your certificate authority
Intermittent timeouts on large answers dig +tcp example.com TXT and dig +bufsize=1232 example.com TXT EDNS buffer/fragmentation problem, or a middlebox dropping big UDP responses

If you take one habit from this guide, take this one: always query the authoritative nameserver directly before you query a public resolver. It separates “the data is wrong” from “the data is right but not visible yet,” and those two problems have completely different fixes and completely different recovery times.

How a Lookup Actually Works (and Where It Breaks)

A resolution is a chain, and every link is a place to fail — and, more importantly, three of those links hold a cache.

  +-------------------------+
  |  Browser / application  |   cache #1   chrome://net-internals/#dns
  +-----------+-------------+
              |
  +-----------v-------------+
  |  OS stub resolver       |   cache #2   systemd-resolved / mDNSResponder /
  |                         |              Windows DNS Client service
  +-----------+-------------+
              |  UDP+TCP 53, DoT 853, DoH 443
  +-----------v-------------+
  |  Recursive resolver     |   cache #3   <== this is what people call
  |  1.1.1.1 / 8.8.8.8 /    |              "propagation"
  |  ISP / corporate fwd    |
  +--+--------+---------+---+
     |        |         |
     |        |         +--> (3) ns1.northwind.example   ANSWER: A 203.0.113.24, TTL 300
     |        +------------> (2) .example TLD registry   REFERRAL: "ask ns1.northwind.example"
     +---------------------> (1) Root servers a-m        REFERRAL: "ask the .example servers"
Figure 1. The resolution chain. Only the recursive resolver caches on the internet’s behalf; the two caches above it are local to the user and invisible to every propagation checker you will ever run.

Walking the same chain in words, with the failure attached to each step:

  1. The application and OS stub resolver. Browsers keep their own cache, as does the operating system. On Windows the DNS Client service caches; on macOS it is mDNSResponder; on modern Linux it is usually systemd-resolved. Each layer can serve a stale answer after the upstream resolver has already refreshed — which is why “it works on my phone but not my laptop” is a cache story, not a DNS story.
  2. The recursive resolver. Your ISP’s resolver, a corporate forwarder, or a public one such as 1.1.1.1, 8.8.8.8 or 9.9.9.9. This is the only component that caches on the internet’s behalf, and it is the entire substance of what people call propagation.
  3. The root zone. Thirteen named root server identities, anycast to hundreds of physical instances (see the IANA root server list). They answer with a referral to the TLD, never with your data.
  4. The TLD registry. Holds your delegation: the NS records for your domain and, where the nameservers sit inside your own domain, the glue A/AAAA records that stop the lookup becoming circular.
  5. Your authoritative nameservers. The only place your actual zone data lives.

Two failure modes at the delegation layer deserve names because their symptoms are so confusing. Lame delegation is when the parent lists a nameserver that does not answer authoritatively for the zone: resolution becomes slow and intermittent as resolvers time out and retry the other servers in the set. Missing glue is when you use in-bailiwick nameservers (for example ns1.example.com serving example.com) without registering their IP addresses at the registrar; the zone is unresolvable from a cold cache while appearing perfectly healthy from any resolver that still has the addresses cached. RFC 8499 is the reference if you want the precise vocabulary for arguing about either one in a post-mortem.

dig +trace walks that entire chain from the root and shows you exactly which step returns something unexpected. It is the single most useful command in DNS, and it deliberately ignores your resolver’s cache — which is precisely why it is useful.

dig +trace example.com A
dig NS example.com @a.gtld-servers.net    # what the parent says
dig NS example.com @ns1.yourprovider.net  # what your zone says

When those last two disagree, you have found your bug. The parent’s copy wins for delegation purposes; the in-zone copy is the one you edit in the control panel, and nobody outside your zone has to believe it.

The DNS Record Types You Actually Touch

You will spend 95 percent of your working life in about eight record types. Our reference on what each DNS record type actually does covers the long tail; what follows is the operational summary, with the gotcha attached to each.

Record What it does The gotcha
A Hostname to IPv4 address Multiple A records give round-robin distribution, not failover; a dead IP stays in rotation until you remove it
AAAA Hostname to IPv6 address A wrong AAAA is worse than none: clients prefer IPv6 and stall before falling back
CNAME Alias one name to another Cannot coexist with any other record at the same name; never valid at the zone apex
ALIAS / ANAME / flattening Provider-side apex alias Vendor-specific, not a protocol feature; TTL and geo behaviour change when you switch provider
MX Mail routing; lowest priority number wins The target must be a hostname with address records, never a CNAME (RFC 2181)
TXT Free-form strings: SPF, DKIM, DMARC, ownership verification Each string is capped at 255 characters; 2048-bit DKIM keys must be split into multiple chunks
NS Delegation to authoritative servers Two copies exist (parent and in-zone); mismatch causes lame delegation
SOA Zone metadata and serial The MINIMUM field sets negative-cache TTL, not record lifetime (RFC 2308)
CAA Which CAs may issue certificates for the name Checked at issuance, so a stale CAA silently blocks an automated renewal months later
PTR Reverse lookup for an IP Lives in the IP owner’s in-addr.arpa zone, not yours; set it via your hosting provider for mail servers
SRV Service location with host and port Underscore labels are part of the name; priority and weight are frequently transposed by hand

Why CNAME at the apex keeps coming up

Because every modern platform wants you to point example.com at a hostname rather than an IP address, and the protocol forbids it. The apex must carry SOA and NS records, and RFC 1035 does not permit a CNAME to sit alongside other data at the same name. The workable answers are: use your provider’s ALIAS/ANAME/flattening feature; redirect the apex to www at the HTTP layer; or accept a static A record and monitor it properly.

What you should not do is copy an apex CNAME between providers and assume identical behaviour. A flattened apex that becomes a literal CNAME after a migration takes mail down with it, because the MX records at the apex are ignored the moment a CNAME appears there — and because mail failures are asynchronous, nobody notices for several hours.

TTL: The Only Setting That Controls Your Blast Radius

TTL is how many seconds a resolver may keep an answer before asking again. It is not really a performance setting; it is a rollback-speed setting. Your TTL is the maximum time it takes to undo a mistake. Treat it as an incident-response parameter and the right values become obvious:

  • Apex and www A/AAAA — 300 to 3600 seconds. Short enough to reroute traffic during an incident without hammering your authoritative servers in normal operation.
  • MX — 3600 to 14400 seconds. Mail routing rarely changes, and sending servers retry for days on failure, so the cost of a longer TTL is low.
  • NS (in-zone) — 86400 seconds. Match the parent delegation TTL as closely as your registry allows; a mismatch here is a classic lint warning and an occasional real bug.
  • TXT for SPF, DKIM and DMARC — 3600 seconds. Fast enough to repair a broken SPF record inside an hour, which is roughly how long it takes for someone to notice.
  • Anything you are about to migrate — 300 seconds. Set it 24 to 48 hours in advance and restore it afterwards.

Two caveats trip people up. First, resolvers may clamp your TTL in both directions: very long TTLs are commonly capped (one day and seven days are both seen in the wild), and some aggressive forwarders and CPE devices enforce a floor, so a 30-second TTL is not a guarantee of 30-second behaviour anywhere except your own authoritative servers. Second, negative answers cache too. If a name did not exist and something queried it, the NXDOMAIN is cached for the interval set by the SOA MINIMUM field, bounded by the SOA record’s own TTL — which is why a brand-new subdomain can look broken for an hour after you create it, with nothing wrong in the zone at all. Our notes on TTL values by record type cover provider-specific clamping behaviour in more detail.

The pre-change TTL runbook

  1. Inventory every record in the path, including CNAME targets, MX hosts and any TXT records that reference the service.
  2. Drop each of them to 300 seconds, at least one full current-TTL period before the change window.
  3. Confirm the short TTL is actually live: query two or three public resolvers and check the TTL counter in the answer section is below 300.
  4. Make the change at the authoritative provider and verify it there first: dig @ns1.provider.net example.com A.
  5. Watch public resolvers until they agree, then restore the longer TTLs.

DNS Propagation Is Cache Expiry, Not a Broadcast

Nothing propagates. There is no gossip protocol pushing your new A record around the world, no queue draining, no sync job you can accelerate by opening a support ticket. Your authoritative servers change instantly; everyone else keeps serving their cached copy until its TTL runs out, at which point they come back and ask. That single mental model dissolves most propagation anxiety, and we unpack the mechanics further in why nothing actually propagates.

The practical consequences are what matter on an incident call:

  • Propagation checker sites sample, they do not measure. They query a fixed list of open resolvers. A red marker means that one resolver’s cache has not expired yet — expected behaviour on a timer you set yourself, not a fault to escalate.
  • You can force two large caches, not the internet. Google Public DNS publishes a cache flush tool and Cloudflare offers an equivalent purge page for 1.1.1.1. Between them that covers a meaningful share of consumer traffic and none of your corporate forwarders.
  • Clear your own layers before escalating anywhere. ipconfig /flushdns on Windows; sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder on macOS; resolvectl flush-caches on systemd Linux; and chrome://net-internals/#dns for Chrome’s own cache, which ignores everything the OS does.
  • A resolver that is still serving the old answer is working correctly. The bug, if there is one, was choosing a long TTL before the change.

Reading dig Output: What the Response Is Telling You

Most guides list commands. The skill that actually shortens outages is reading the response rather than skimming the answer line, so here is real output, annotated. A fuller command reference lives in worked examples of every dig flag.

Anatomy of a healthy response

$ dig @1.1.1.1 northwind.example A

; <<>> DiG 9.18.28 <<>> @1.1.1.1 northwind.example A
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 41287
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;northwind.example.		IN	A

;; ANSWER SECTION:
northwind.example.	287	IN	A	203.0.113.24

;; Query time: 4 msec
;; SERVER: 1.1.1.1#53(1.1.1.1) (UDP)
;; WHEN: Tue Sep 15 09:14:02 UTC 2026
;; MSG SIZE  rcvd: 72

Four things in that block are worth more than the IP address:

  • status: NOERROR with ANSWER: 1 — the name exists and has a record of the type you asked for.
  • flags: qr rd ra — no aa, so this is a cached answer from a recursive resolver, not an authoritative one. No ad either, so the answer was not DNSSEC-validated (here, because the zone is unsigned).
  • 287 in the answer section — the remaining lifetime of the cached copy, not the TTL you configured. The zone’s published value is 300.
  • udp: 1232 in the OPT pseudosection — the advertised EDNS buffer size, which is the first thing to check when large answers time out.

Run the identical query eleven seconds later and the countdown proves you are reading cache, not the zone:

$ dig @1.1.1.1 northwind.example A +noall +answer
northwind.example.	276	IN	A	203.0.113.24

$ dig @ns1.northwind.example northwind.example A +noall +answer +comments | head -4
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 5502
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 2, ADDITIONAL: 1
northwind.example.	300	IN	A	203.0.113.24

The authoritative server returns the full 300 every time and sets aa. If the two IP addresses differ, you are watching a TTL expire and there is nothing to fix but patience. If they are identical and users still report a problem, DNS is not your outage.

The status codes, and what each one means operationally

  • NOERROR with an empty answer section (NODATA) — the name exists but has no record of that type. Common when something asks for AAAA on an IPv4-only host. Different bug from NXDOMAIN, and often not a bug at all.
  • NXDOMAIN — the name does not exist anywhere in the zone. Check spelling, then check you are looking at the zone the domain is actually delegated to.
  • SERVFAIL — the resolver could not complete the lookup. On a validating resolver, assume DNSSEC until proven otherwise; then look for timeouts and lame delegation.
  • REFUSED — you asked a server that is neither authoritative for the zone nor willing to recurse for you. Usually means you typed the wrong nameserver.
  • flags: aa — you are talking to an authoritative server. flags: ad — the answer was DNSSEC-validated. Absence of ad on a zone you believe is signed is a red flag worth chasing.

nslookup and Resolve-DnsName on Windows

nslookup -type=mx example.com 1.1.1.1
nslookup -type=txt _dmarc.example.com
nslookup
> set debug
> set type=ns
> example.com

Enable set debug (or set d2 for the full packet) or you are working blind: without it, nslookup hides the response codes and TTLs you need to distinguish a cache problem from a data problem. On any modern Windows build, PowerShell’s Resolve-DnsName -Name example.com -Type A -Server 8.8.8.8 is the better native tool — it returns TTLs as a real field you can sort and filter.

Email Authentication: SPF, DKIM and DMARC as DNS Problems

Mail deliverability failures are DNS failures roughly as often as they are content failures. Since Google and Yahoo tightened their bulk sender requirements in February 2024, senders above roughly 5,000 messages per day to Gmail need SPF, DKIM and DMARC in place, one-click unsubscribe on marketing mail, and a reported spam rate held below 0.3 percent. Our walkthrough on setting up SPF, DKIM and DMARC from scratch covers implementation; this section covers diagnosis.

SPF: one record, ten lookups

RFC 7208 imposes limits that break real deployments, quietly:

  • Exactly one SPF TXT record per domain. Two v=spf1 records is a PermError, and most receivers treat a PermError as a fail. You merge SPF records by combining their mechanisms into one string, never by publishing a second record.
  • A hard cap of 10 DNS-querying mechanisms (include, a, mx, ptr, exists, redirect), counted recursively. Three SaaS senders can exhaust the budget on their own because each include expands into further includes.
  • A limit of two void lookups. Includes that point at domains which no longer exist count against you — a decommissioned vendor can break a record you never edited.
  • -all versus ~all. Hard fail is correct once you are confident the record is complete; softfail is the honest transitional state. The deprecated SPF RR type (type 99) should not be used — SPF lives in TXT.

The duplicate-record failure is trivial to spot once you look for it, and invisible in most control panels:

$ dig TXT northwind.example +short
"v=spf1 include:_spf.google.com include:sendgrid.net ~all"
"v=spf1 include:servers.mcsv.net ~all"
"MS=ms84213907"
"atlassian-domain-verification=9Yh1x..."

Two v=spf1 strings, published six months apart by two different teams: PermError for every receiver, and SPF effectively switched off. The fix is one record — "v=spf1 include:_spf.google.com include:sendgrid.net include:servers.mcsv.net ~all" — then re-count the lookups it expands into before anyone adds a fourth vendor.

DKIM: selectors and key hygiene

DKIM (RFC 6376) publishes a public key at selector._domainkey.example.com. Prefer 2048-bit keys, remembering that a 2048-bit key exceeds the 255-character TXT string limit and must be split into multiple quoted strings that the resolver concatenates — a step some control panels perform silently and others leave to you, producing a key that looks present and verifies nothing. Give each sending platform its own selector so you can rotate or revoke one without touching the others, and delete selectors when you offboard a vendor. A live DKIM key for a platform you stopped paying for is a standing authorisation to send as you.

DMARC: the alignment trap

DMARC (RFC 7489) ties SPF and DKIM to the domain your recipients actually see. A message passes DMARC when SPF passes and the Return-Path domain aligns with the From: header domain, or when DKIM passes and the signing d= domain aligns. Relaxed alignment allows a subdomain to match the organisational domain; strict alignment does not.

On the standards status, to be precise rather than vague: the successor specification is DMARCbis, carried in the IETF DMARC working group as draft-ietf-dmarc-dmarcbis. Its substantive changes are replacing the Public Suffix List with a DNS “tree walk” for discovering the organisational domain, adding the np= tag for non-existent subdomains, and deprecating pct= and rf=. At the time of review (September 2026) the draft had cleared working-group last call and was in the RFC Editor process rather than published as a numbered RFC. Deploy against RFC 7489 semantics today, but check the draft’s current state on the IETF datatracker before you rely on np= or on tree-walk behaviour, because receiver support lags publication by a long way.

Symptom Check Likely cause
SPF passes, DMARC fails Authentication-Results header for spf=pass, plus the Return-Path domain Envelope sender is the vendor’s domain, so nothing aligns. Fix with a custom Return-Path or aligned DKIM
DMARC fails only on forwarded mail Whether the DKIM signature survived the hop Forwarding breaks SPF by design; aligned DKIM is what carries mail through lists and forwarders
Everything fails after adding a vendor dig TXT example.com for multiple v=spf1 strings Duplicate SPF records, or the 10-lookup limit exceeded
Subdomain mail rejected, apex fine The sp= tag in the DMARC record Subdomain policy inherits or overrides in ways people forget to test
No aggregate reports arriving The rua= address and cross-domain authorisation Reporting to an address outside the domain requires a matching _report._dmarc TXT record on the receiving domain

Roll out in the documented order: publish p=none with a rua= reporting address; read aggregate reports for two to four weeks until every legitimate source is authenticated and aligned; move to p=quarantine; then to p=reject. Skipping straight to reject is how internal invoices stop arriving and nobody finds out until month-end.

DNSSEC Without the Outages

DNSSEC (RFC 4033 and its companions) signs your records so a validating resolver can prove they were not tampered with in transit. The chain of trust runs from the root, through the TLD, to a DS record held at your registrar that must hash your zone’s key-signing key.

Root zone (trust anchor shipped with every validating resolver)
   |  signs
   v
.example registry  --  publishes DS for northwind.example   <== your registrar writes this
   |  hash must match
   v
northwind.example zone
   |-- DNSKEY  KSK  (key tag 61234)   <== the DS must hash THIS key
   |-- DNSKEY  ZSK  (key tag 20195)
   +-- RRSIG over every RRset         <== each one carries an explicit expiry date
Figure 2. The DNSSEC chain of trust. Two links sit outside your DNS provider — the DS at the registrar and the trust anchor at the root — and the first of those is where nearly every self-inflicted DNSSEC outage happens.

When any link breaks, validating resolvers do not degrade gracefully: they return SERVFAIL. Your domain disappears for a large share of the internet while resolving perfectly from any non-validating resolver you happen to test with. We walk the key hierarchy in more depth in how the DNSSEC chain of trust is built. The three failure modes that account for almost everything we see:

  1. Stale DS after a provider change. The domain moves, the DS record is carried across, but the gaining DNS provider generates a fresh key-signing key. The DS at the registry now hashes a key that no longer exists.
  2. Expired signatures. RRSIG records carry explicit validity windows. A self-hosted zone whose re-signing cron failed goes dark at a precise moment, with no configuration change to correlate against.
  3. Broken algorithm rollovers. Moving from RSA to ECDSA (algorithm 13, the modern default) requires both algorithms to be present and correctly signed throughout the transition.
dig example.com A                        # SERVFAIL from a validating resolver?
dig +cd example.com A                    # checking disabled: if this works, DNSSEC is the fault
dig DS example.com @a.gtld-servers.net   # what the parent publishes
dig DNSKEY example.com +multiline        # what the zone actually holds
delv example.com A +rtrace               # the full validation path, with reasons

Compare the key tag and digest in the parent’s DS against the DNSKEY set in the zone. If they do not correspond, you have found the outage. Keep in mind that the fix is bounded by the parent’s TTL, which you do not control, so DNSSEC incidents last measurably longer than ordinary record mistakes. That asymmetry is the whole argument for changing DS records deliberately and never opportunistically.

Case File: northwind.example Goes Dark for Half the Internet

A worked example is worth more than another table. The domain, addresses and key tags below are from a lab reproduction of an incident pattern we have handled several times; the command sequence is exactly the one we run.

09:07. Support forwards three tickets: the site is unreachable. Two colleagues on the office network see it fine. Nothing was deployed overnight. The only change in the last week was a registrar transfer completed on Friday.

09:09 — reproduce from a public resolver.

$ dig @8.8.8.8 northwind.example A

;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 9134
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;northwind.example.		IN	A

;; Query time: 812 msec
;; SERVER: 8.8.8.8#53(8.8.8.8) (UDP)

SERVFAIL, no answer section. Note what this does not tell you: whether the data is missing or the validation failed.

09:10 — ask the authoritative server directly.

$ dig @ns1.northwind.example northwind.example A +noall +comments +answer
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 33018
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 2, ADDITIONAL: 1
northwind.example.	300	IN	A	203.0.113.24

The data is present and the aa flag confirms it is authoritative. So this is not a missing record — it is a resolver refusing to hand it over.

09:11 — disable validation and compare.

$ dig +cd @8.8.8.8 northwind.example A +noall +comments +answer
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 27740
;; flags: qr rd ra cd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
northwind.example.	288	IN	A	203.0.113.24

Same resolver, same query, one extra flag: NOERROR. SERVFAIL with validation, NOERROR without it. That is a DNSSEC failure and nothing else, confirmed in four seconds. Diagnosis time so far: about ninety seconds.

09:13 — find which link broke.

$ delv @8.8.8.8 northwind.example A +rtrace
;; fetch: northwind.example/A
;; fetch: northwind.example/DNSKEY
;; fetch: northwind.example/DS
;; no valid RRSIG resolving 'northwind.example/DNSKEY/IN'
;; broken trust chain resolving 'northwind.example/A/IN': 203.0.113.53#53
;; resolution failed: broken trust chain

$ dig DS northwind.example @a.gtld-servers.net +noall +answer
northwind.example.	86400	IN	DS	61234 13 2 4F9C2B...E71A

$ dig DNSKEY northwind.example @ns1.northwind.example +multiline | grep "key id"
	; ZSK; alg = ECDSAP256SHA256 ; key id = 20195
	; KSK; alg = ECDSAP256SHA256 ; key id = 34219

The parent publishes a DS for key tag 61234. The zone holds keys 20195 and 34219. Key 61234 belonged to the old provider and was destroyed during Friday’s transfer. Every validating resolver on earth has been correctly refusing to trust the zone since its cached DNSKEY expired over the weekend; every non-validating one — including the office forwarder the two unaffected colleagues use — never noticed.

09:20 — fix, in the only order that works. Publish the correct DS for key tag 34219 at the registrar, or delete the DS entirely if the new provider’s signing is not yet ready. Deletion is the faster rollback, because going insecure needs only the parent’s negative proof to refresh, whereas a corrected DS still has to wait out the 86400-second DS TTL in resolver caches. Then verify from outside your own assumptions:

$ dig DS northwind.example @a.gtld-servers.net +noall +answer
northwind.example.	86400	IN	DS	34219 13 2 A0D51C...9B42

$ dig @8.8.8.8 northwind.example A +noall +comments +answer
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 14402
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
northwind.example.	300	IN	A	203.0.113.24

The ad flag is the proof: the answer was validated, not merely returned. Cross-check the full chain at DNSViz, which renders the same analysis as a graph and is useful evidence for a post-mortem.

The rule we adopted afterwards: remove the DS record first, wait for the parent TTL to expire, migrate, then re-publish the new DS. Four steps, one of which is doing nothing for a day, and it converts the highest-severity DNS failure mode into a non-event.

Changing Nameservers Without Downtime

A nameserver migration is the highest-risk routine change in DNS, because the parent TTL is long and the failure is total rather than partial. This sequence has never failed us:

  1. Export the existing zone in full. Every record, not just the ones you remember. Missing TXT verification records are the classic casualty, and you only discover them when a SaaS integration silently deauthorises.
  2. Remove DNSSEC first if the zone is signed. Delete the DS at the registrar, then wait out the parent TTL (commonly 86400 to 172800 seconds) before going any further.
  3. Build the zone at the new provider and test it directly before touching delegation: dig @ns1.newprovider.net example.com A, plus MX, TXT and every CNAME in the file.
  4. Lower record TTLs at the old provider to 300 seconds, and let the previous TTL expire before proceeding.
  5. Run both providers in parallel with identical data if the registrar allows mixed NS sets, or at minimum leave the old zone intact and serving for 72 hours after the switch. Resolvers holding cached NS records will keep asking the old servers, and those servers must keep giving correct answers.
  6. Switch the NS records at the registrar and monitor with dig +trace from several different networks, not just your office.
  7. Re-publish DNSSEC only after the migration is stable and the new provider’s keys are live and signing.
  8. Restore steady-state TTLs, and only then decommission the old zone.

Monitoring and Hygiene: What to Check Quarterly

  • Domain and DNS expiry. Registrar auto-renew on, payment card current, registrant email on a domain you still control. A lapsed registration is unrecoverable in a way a bad record never is.
  • Dangling CNAMEs. CNAMEs pointing at decommissioned cloud buckets or SaaS subdomains are the standard subdomain-takeover vector. Audit every CNAME whose target you no longer own.
  • SPF lookup count. Re-count after every marketing tool your organisation adopts, including the ones adopted without telling you.
  • Orphan DKIM selectors. Delete keys for vendors you have left.
  • CAA records. Confirm they still name the CA your automation actually uses, including any backup issuer.
  • RRSIG expiry alerts for self-hosted signed zones, alarming days before expiry rather than hours.
  • EDNS compliance. Test your authoritative servers against the DNS Flag Day checks; non-compliant servers behave erratically with modern resolvers and produce exactly the intermittent timeouts nobody can reproduce.
  • External monitoring of resolution itself from multiple regions, not just an HTTP check. An HTTP monitor using a cached IP stays reassuringly green while your DNS is down for everyone else.

The short version

  • Query the authoritative nameserver first, then public resolvers. The difference between those two answers tells you whether the problem is data or cache.
  • dig +trace for delegation problems, dig +cd for SERVFAIL, dig @resolver for cache questions, dig TXT for anything involving mail.
  • Read the header, not just the answer: aa, ad, the status code and the TTL countdown answer most questions before you touch a control panel.
  • TTL is your rollback speed. Drop it to 300 seconds a day before any change and restore it afterwards.
  • Propagation is cache expiry, not a push. Only NS changes are genuinely bound by the 24–48 hour figure.
  • SPF must be one record under ten lookups; DKIM needs a selector per vendor; DMARC fails on alignment far more often than on authentication.
  • With DNSSEC, remove the DS before a provider change and re-publish after. The parent TTL decides how long your mistake lasts.

Structured data on this page

For transparency, the FAQ block below is emitted as FAQPage JSON-LD in the page <head>, alongside TechArticle and BreadcrumbList markup. All six questions are included; two are shown here so you can verify the shape, and the live page validates against the Schema.org Markup Validator and Google’s Rich Results Test.

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "FAQPage",
  "mainEntity": [
    {
      "@type": "Question",
      "name": "Why do I get SERVFAIL from some resolvers but not others?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Usually a DNSSEC validation failure. Validating resolvers return SERVFAIL when a signature does not verify, while a non-validating resolver returns the record. Confirm with dig +cd: if checking-disabled works and the plain query does not, DNSSEC is the fault."
      }
    },
    {
      "@type": "Question",
      "name": "How long does DNS propagation really take?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "The TTL that was on the old record when a resolver last fetched it, plus local browser and OS caches. NS changes are bounded by the parent registry TTL, commonly 172800 seconds, which you cannot shorten."
      }
    }
  ]
}
</script>

Protocol behaviour described above is drawn from the cited RFCs and from current vendor documentation as reviewed on 15 September 2026. Command output is captured from BIND 9.18 against a lab zone, with addresses replaced by RFC 5737 documentation ranges and .example names per RFC 2606. Operational TTL values and runbook steps are our own production practice rather than standards requirements, and should be adjusted to your risk tolerance. Registry and registrar TTLs vary by TLD — verify yours before scheduling a delegation change. Corrections to the author.

Frequently Asked Questions

How long does DNS propagation really take?

Work it out rather than guessing: worst case equals the TTL that was on the old record the last time a resolver fetched it, plus any client-side cache in front of the user (browser and OS stub caches, typically 60 seconds to a few minutes). A record that was published at 3600 seconds can therefore still be served for roughly an hour and a bit after you change it, even though your authoritative servers updated the instant you hit save. Two exceptions push the number up: nameserver (NS) changes are bounded by the parent registry’s delegation TTL, commonly 172800 seconds and not shortenable by you; and a previously cached NXDOMAIN for a name you have just created expires on the SOA MINIMUM timer, not the new record’s TTL. Lower the TTL to 300 seconds one full old-TTL period before a planned change and the arithmetic collapses to minutes.

What is the difference between dig and nslookup?

dig shows you the raw protocol; nslookup shows you a summary. dig prints the full response including the header flags (aa, rd, ra, ad, cd), the response status (NOERROR, NXDOMAIN, SERVFAIL, REFUSED), the TTL remaining on the cached answer, the answer/authority/additional sections, the EDNS OPT pseudosection and the resolver that replied. nslookup hides most of that unless you enable debug mode with ‘set debug’ or ‘set d2’, and on some platforms it silently retries over another transport, which can mask the exact failure you are trying to diagnose. Use dig (or kdig, drill, or delv when you need validation detail) for diagnosis. On a stock Windows box, PowerShell’s Resolve-DnsName is a better native choice than nslookup because it exposes record TTLs directly.

Why do I get SERVFAIL from some resolvers but not others?

The usual cause is a DNSSEC validation failure. Validating resolvers such as 8.8.8.8, 1.1.1.1 and 9.9.9.9 return SERVFAIL when a signature does not verify, while a non-validating resolver on the same network returns the record happily, which is why the outage looks intermittent and user-specific. Confirm it in one step by re-running the query with checking disabled: if ‘dig +cd example.com A’ returns NOERROR and the plain query returns SERVFAIL, DNSSEC is the fault. The three common triggers are an expired RRSIG, a DS record at the registrar that no longer hashes the zone’s current key-signing key after a provider change, and an incomplete algorithm rollover. Non-DNSSEC causes worth ruling out: an authoritative server that is timing out, a lame delegation, and large responses being dropped by a middlebox before they reach the resolver.

Can I use a CNAME at the root of my domain?

No. A CNAME cannot coexist with any other record at the same name, and the zone apex must hold SOA and NS records, so an apex CNAME is invalid per RFC 1034 and RFC 2181. In practice resolvers and validators handle the illegal combination inconsistently, and the most common casualty is mail: the MX records at the apex stop being honoured the moment a CNAME appears there. Use a provider feature instead — ALIAS, ANAME or CNAME flattening resolves the target at the authoritative server and hands A/AAAA records back to the client. These are vendor implementations rather than protocol features, and they differ in how they handle TTLs, geo-steering and IPv6, so re-test the apex after any DNS provider migration instead of assuming the behaviour carried over.

Why is my mail failing DMARC when SPF passes?

Because DMARC checks alignment, not just authentication. SPF passes against the envelope sender (the Return-Path / MAIL FROM domain), but DMARC requires that domain to align with the visible From: header domain. A marketing platform sending as [email protected] while your From: header says [email protected] produces an SPF pass and a DMARC fail, every time. The fix is either a custom Return-Path on your own domain (usually a CNAME the vendor provides) or a DKIM signature whose d= tag is your domain, since a DKIM pass with alignment also satisfies DMARC. Read the failing message’s Authentication-Results header: it tells you which of spf= and dkim= passed and, crucially, which domain each one authenticated. Aligned DKIM is also the only mechanism that survives forwarding and mailing lists, so fix DKIM alignment first if mail breaks only on forwarded copies.

What TTL should I set before a DNS migration?

Drop the record to 300 seconds at least one full old-TTL period before the change, make the change, verify from several public resolvers, then raise it back to 3600 seconds or higher once the new answer is stable. Lower the TTL on everything in the path — MX hosts, CNAME targets and any TXT records the service depends on — not just the A record. Two constraints you cannot engineer around: the SOA MINIMUM field governs negative caching of NXDOMAIN responses under RFC 2308, so a name that was queried before it existed carries a cached negative answer that must also expire; and NS records at the parent registry usually cannot be shortened at all, which is why nameserver changes are the slowest and riskiest kind of DNS change.