Introduction

DNS propagation delayed or taking too long occurs when DNS record changes are not visible globally within the expected timeframe. "DNS propagation" is actually a combination of caching at multiple layers: ISP resolvers, corporate DNS servers, operating system caches, browser caches, and authoritative nameserver updates. When propagation seems stuck, users may see old IP addresses, broken subdomains, or intermittent resolution failures. Common causes include high TTL values set before the change, caching at intermediate resolvers, old nameservers still serving stale data, or DNSSEC validation failures blocking new records.

Symptoms

  • DNS changes visible from some locations but not others
  • dig shows new record but browser/clients still use old IP
  • DNS resolves correctly on one ISP but not another
  • Subdomain works on mobile network but not home/office WiFi
  • Changes made 24+ hours ago but some users still see old records
  • Issue appears after nameserver change, DNS provider migration, A/AAAA record update, or DNSSEC enablement

Common Causes

  • TTL (Time To Live) value too high before record change
  • ISP resolver ignoring TTL and caching beyond expiration
  • Old nameservers still authoritative and serving stale records
  • Parent nameservers (TLD) pointing to old nameservers
  • DNSSEC signatures (RRSIG) invalid or expired for new records
  • Corporate DNS servers with extended cache times
  • Browser DNS cache not flushing after record change
  • CNAME chains causing extended resolution delays

Step-by-Step Fix

### 1. Check current TTL values

Verify TTL configuration:

```bash # Check TTL for specific record dig example.com A +nocmd +noall +answer +ttid

# Output: # example.com. 300 IN A 192.0.2.1 # ^^^ # TTL in seconds (300 = 5 minutes)

# Check TTL for all record types dig example.com ANY +nocmd +noall +answer +ttid

# Check nameserver TTL dig example.com NS +nocmd +noall +answer +ttid

# Check SOA record (contains default TTL and negative cache TTL) dig example.com SOA +nocmd +noall +answer

# Output: # example.com. 3600 IN SOA ns1.example.com. admin.example.com. ( # 2024010101 ; serial # 7200 ; refresh (2 hours) # 3600 ; retry (1 hour) # 1209600 ; expire (2 weeks) # 3600 ; minimum/negative TTL (1 hour) # ) ```

TTL recommendations: - **Before changes**: Reduce TTL to 300 (5 minutes) at least 24-48 hours before - **A/AAAA records**: 300-3600 (5 min - 1 hour) - **CNAME records**: 3600 (1 hour) - **MX records**: 3600-14400 (1-4 hours) - **NS records**: 86400 (24 hours) - **TXT records**: 300-3600 (5 min - 1 hour)

### 2. Reduce TTL before making changes

Lower TTL in advance of changes:

```bash # At your DNS provider, update TTL 24-48 hours BEFORE the change:

# Cloudflare: # DNS > Records > Edit > TTL > Auto (minimum) or 300

# AWS Route53: # Hosted zones > example.com > Records > Edit record # TTL: 300 seconds

# GoDaddy: # DNS Management > Records > Edit > TTL: 1/2 Hour

# Command line with AWS CLI: aws route53 change-resource-record-sets \ --hosted-zone-id Z1234567890 \ --change-batch file://lower-ttl.json

# lower-ttl.json: { "Changes": [{ "Action": "UPSERT", "ResourceRecordSet": { "Name": "example.com", "Type": "A", "TTL": 300, "ResourceRecords": [{"Value": "192.0.2.1"}] } }] }

# After migration complete, increase TTL back to reduce queries ```

### 3. Flush local DNS cache

Clear caches at all layers:

```bash # Windows - Flush DNS ipconfig /flushdns

# macOS - Flush DNS (varies by version) sudo dscacheutil -flushcache sudo killall -HUP mDNSResponder

# Ubuntu/Debian (systemd-resolved) sudo systemctl restart systemd-resolved sudo resolvectl flush-caches

# RHEL/CentOS (nscd) sudo systemctl restart nscd sudo nscd -i hosts

# Browser DNS cache # Chrome: chrome://net-internals/#dns > Clear host cache # Firefox: about:networking#dns > Clear DNS Cache # Edge: edge://net-internals/#dns > Clear host cache

# Verify cache cleared ping example.com # Should show fresh DNS lookup ```

### 4. Check nameserver delegation

Verify parent nameservers point to correct nameservers:

```bash # Check which nameservers are authoritative dig example.com NS +trace

# Output shows delegation chain: # . (root) -> com. (TLD) -> example.com (authoritative) # Look for inconsistencies at each level

# Check TLD nameservers know about your nameservers dig example.com NS @a.gtld-servers.net

# Check your authoritative nameservers respond dig @ns1.your-dns-provider.com example.com A dig @ns2.your-dns-provider.com example.com A

# Verify all nameservers return same answer for ns in ns1 ns2 ns3 ns4; do echo "Querying $ns..." dig @$ns.example.com example.com A +short done ```

Fix delegation issues:

```bash # If TLD has wrong nameservers, update at registrar: # Go to domain registrar (GoDaddy, Namecheap, etc.) # Domain Settings > Nameservers > Update

# Changes at registrar take 24-48 hours to propagate to TLD

# Verify update with whois whois example.com | grep -A5 "Name Server"

# Or use registrar's WHOIS tool ```

### 5. Check for stale records at old provider

Old DNS provider may still serve stale records:

```bash # Query old nameservers directly dig @old-ns1.previous-provider.com example.com A dig @old-ns2.previous-provider.com example.com A

# If old records still respond: # 1. Update records at old provider to match new # 2. Or remove zone from old provider # 3. Or change nameservers at old provider to point to new

# Common scenario: Nameserver change at registrar # but old provider still has zone active

# At old provider admin panel: # - Delete the zone entirely, OR # - Update nameserver records to point to new provider ```

Propagation timeline: - **Nameserver change at registrar**: 24-48 hours to TLD - **Record change at provider**: Minutes to hours (depends on TTL) - **ISP resolver cache**: Up to TTL value (can be longer)

### 6. Check DNSSEC validation

DNSSEC failures block resolution:

```bash # Check DNSSEC status dig example.com DNSKEY +dnssec dig example.com RRSIG +dnssec

# Check for validation errors dig example.com A +dnssec +multiline

# Output with DNSSEC failure: # ;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL # ;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1 # status: SERVFAIL indicates DNSSEC validation failure

# Check DS record at parent dig example.com DS +trace

# Verify DNSSEC chain dnssec-verify example.com

# Or use online tools # https://dnschecker.org/dnssec.php?domain=example.com ```

Fix DNSSEC issues:

```bash # If you changed nameservers, DNSSEC may be broken # Steps to fix:

# 1. Get new DS record from new provider # At new provider: Get DS record for delegation

# 2. Update DS record at registrar # Go to registrar > DNSSEC > Update DS record

# 3. Wait for TTL to expire (usually 24 hours)

# 4. If urgent, temporarily disable DNSSEC # Registrar > DNSSEC > Disable/Remove DS record # WARNING: This removes DNSSEC protection

# 5. Re-enable DNSSEC with new keys after propagation ```

### 7. Check ISP resolver caching

ISP resolvers may cache beyond TTL:

```bash # Test from multiple resolvers dig @8.8.8.8 example.com A # Google dig @1.1.1.1 example.com A # Cloudflare dig @9.9.9.9 example.com A # Quad9 dig @208.67.222.222 example.com A # OpenDNS

# If results differ: # - Google/Cloudflare show new IP: Your change is correct # - ISP resolver shows old IP: ISP caching issue

# Force ISP resolver refresh (not always possible): # 1. Wait for TTL to expire # 2. Contact ISP to flush their cache # 3. Use public DNS (8.8.8.8, 1.1.1.1) as workaround

# Check ISP resolver TTL adherence dig @isp-resolver example.com A +nocmd +noall +answer +ttid # If TTL shows high value but should be low, ISP ignoring TTL ```

Common ISP behaviors: - **Comcast/Xfinity**: Generally respects TTL, 2-4 hour max cache - **Verizon Fios**: May cache up to 24 hours regardless of TTL - **AT&T**: Known to cache MX records for 24+ hours - **Spectrum**: Usually respects TTL - **Corporate ISPs**: Often have extended cache policies

### 8. Check CNAME chain resolution

Long CNAME chains cause delays:

```bash # Check for CNAME chains dig www.example.com +trace

# Output showing chain: # www.example.com. 300 IN CNAME cdn.example.com. # cdn.example.com. 300 IN CNAME d123.cloudfront.net. # d123.cloudfront.net. 60 IN A 54.192.0.1

# Each CNAME adds resolution time # Some resolvers may cache intermediate records longer

# Check each link in chain dig www.example.com CNAME dig cdn.example.com CNAME dig d123.cloudfront.net A ```

Flatten CNAME chains:

```bash # Instead of: # www -> cdn -> cloudfront -> IP

# Use: # www -> IP (A record directly to final IP)

# Or use CNAME flattening (Cloudflare, Route53): # Cloudflare: CNAME at apex is automatically flattened # Route53: Use ALIAS record type

# AWS Route53 ALIAS: aws route53 change-resource-record-sets \ --hosted-zone-id Z123456 \ --change-batch '{ "Changes": [{ "Action": "CREATE", "ResourceRecordSet": { "Name": "www.example.com", "Type": "A", "AliasTarget": { "HostedZoneId": "Z35SXDOTRQ7X7K", # CloudFront zone "DNSName": "d123.cloudfront.net", "EvaluateTargetHealth": false } } }] }' ```

### 9. Use DNS propagation check tools

Verify propagation status globally:

```bash # Command line tools dnscheck.example.com example.com

# Online propagation checkers: # - https://dnschecker.org/ # - https://www.whatsmydns.net/ # - https://dnspropagation.net/ # - https://intoDNS.com/

# These show DNS status from 20+ locations worldwide # Green checkmarks = propagated # Red X = still showing old records

# API-based checking (for automation) curl -s "https://dnschecker.org/api/dns-record?domain=example.com&type=A" | jq

# Monitor propagation over time watch -n 60 'dig @8.8.8.8 example.com A +short' ```

### 10. Implement DNS change best practices

Prevent future propagation issues:

```yaml # Pre-change checklist (48 hours before): # - [ ] Reduce TTL to 300 seconds for all changing records # - [ ] Document current DNS configuration # - [ ] Verify access to old and new DNS providers # - [ ] Prepare DNSSEC DS records if applicable

# Change day checklist: # - [ ] Create records at new provider # - [ ] Verify records respond correctly # - [ ] Update nameservers at registrar (if migrating) # - [ ] Update DS records for DNSSEC (if applicable) # - [ ] Test from multiple resolvers

# Post-change checklist (24-48 hours after): # - [ ] Verify propagation from multiple locations # - [ ] Check analytics for traffic drop (indicates resolution issues) # - [ ] Monitor DNS query volume at old provider # - [ ] Wait for old TTL to fully expire before decommissioning # - [ ] Increase TTL back to normal values (if desired) ```

Emergency rollback:

```bash # If propagation issues cause outage: # 1. Immediately revert DNS at provider # 2. Keep old infrastructure running during rollback # 3. Users will recover as their cache expires

# For nameserver changes: # 1. Revert nameservers at registrar # 2. Ensure old provider has correct records # 3. Wait 24-48 hours for TLD propagation

# Document what went wrong: # - TTL too high before change # - DNSSEC not properly transferred # - Old provider still serving stale records # - CNAME chain too long ```

Prevention

  • Always reduce TTL to 300 seconds at least 24-48 hours before changes
  • Use DNS provider with low minimum TTL (Cloudflare: 300s, Route53: 1s)
  • Avoid CNAME chains - use A records or ALIAS where possible
  • Keep DNSSEC DS records updated at registrar during migrations
  • Test DNS changes in staging with separate subdomain first
  • Monitor DNS propagation with automated checks during migrations
  • Document DNS provider access and rollback procedures
  • **NXDOMAIN**: Domain or record does not exist
  • **SERVFAIL**: DNS server failure, often DNSSEC-related
  • **REFUSED**: DNS server refused query
  • **FORMERR**: DNS server could not parse query