DNS Debugging Tools

Master dig, nslookup, drill, dog, and online diagnostic tools — with practical debugging scenarios and output walkthroughs.

When DNS breaks, you need to diagnose it fast. Understanding the resolution process is essential for effective debugging. The good news: DNS is one of the most debuggable protocols on the internet. The bad news: most developers don’t know how to read the output of the tools they’re using.

Let’s fix that.

dig — The Swiss Army Knife

dig (Domain Information Groper) is the gold standard for DNS debugging. It’s installed by default on most Unix/Linux/macOS systems and gives you complete, unfiltered DNS query results.

Basic Usage

# Simple A record lookup
$ dig example.com

# Query a specific record type
$ dig example.com AAAA
$ dig example.com MX
$ dig example.com TXT
$ dig example.com NS

# Query a specific nameserver
$ dig example.com @8.8.8.8
$ dig example.com @1.1.1.1

Reading dig Output Like a Pro

Here’s a full dig response, annotated:

$ dig www.example.com

; <<>> DiG 9.18.18 <<>> www.example.com      ← Tool version and query
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 12345
;;              ↑                        ↑
;;              Query type               NOERROR = success
;;                                       NXDOMAIN = name doesn't exist
;;                                       SERVFAIL = server error
;;                                       REFUSED = server refused
;;
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;;        ↑  ↑  ↑
;;        │  │  └── Recursion Available (server supports recursion)
;;        │  └───── Recursion Desired (we asked for recursion)
;;        └──────── Query Response (this is a response, not a query)

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232    ← EDNS0 support, max UDP size

;; QUESTION SECTION:                       ← What we asked
;www.example.com.               IN      A

;; ANSWER SECTION:                         ← The actual answer
www.example.com.        3600    IN      A       93.184.216.34
;;                      ↑ TTL (seconds remaining in cache)

;; Query time: 23 msec                    ← How long the query took
;; SERVER: 192.168.1.1#53(192.168.1.1)   ← Which resolver answered
;; WHEN: Sun Mar 01 12:00:00 EST 2026
;; MSG SIZE  rcvd: 62                     ← Response size in bytes

Essential dig Options

# Short output (just the answer)
$ dig example.com +short
93.184.216.34

# Trace the full resolution path (root → TLD → authoritative)
$ dig example.com +trace
.                       86400   IN      NS      a.root-servers.net.
com.                    172800  IN      NS      a.gtld-servers.net.
example.com.            172800  IN      NS      ns1.example.com.
example.com.            3600    IN      A       93.184.216.34

# Show only the answer section
$ dig example.com +noall +answer
example.com.            3600    IN      A       93.184.216.34

# Query with TCP instead of UDP
$ dig example.com +tcp

# Set a custom timeout (seconds)
$ dig example.com +time=2

# Disable recursion (query as if you're a resolver)
$ dig example.com +norecurse @ns1.example.com

# Check DNSSEC signatures
$ dig example.com +dnssec

# Query for ANY records (often rate-limited nowadays)
$ dig example.com ANY

# Reverse DNS lookup
$ dig -x 93.184.216.34

dig +trace: Following the Resolution Chain

The +trace flag is incredibly powerful for debugging. It starts at the root and follows the delegation chain, showing you every step:

$ dig www.example.com +trace

; <<>> DiG 9.18.18 <<>> www.example.com +trace
.                   518400  IN  NS  a.root-servers.net.
.                   518400  IN  NS  b.root-servers.net.
;; Received 239 bytes from 192.168.1.1#53 in 1 ms

com.                172800  IN  NS  a.gtld-servers.net.
com.                172800  IN  NS  b.gtld-servers.net.
;; Received 828 bytes from 198.41.0.4#53(a.root-servers.net) in 12 ms

example.com.        172800  IN  NS  ns1.example.com.
example.com.        172800  IN  NS  ns2.example.com.
;; Received 498 bytes from 192.5.6.30#53(a.gtld-servers.net) in 25 ms

www.example.com.    3600    IN  A   93.184.216.34
;; Received 62 bytes from 199.43.135.53#53(ns1.example.com) in 18 ms

This tells you: root servers → .com TLD servers → example.com authoritative servers → final answer. If there’s a break anywhere in this chain, +trace will reveal it.

nslookup — Cross-Platform Companion

nslookup is available on virtually every operating system, including Windows. It’s less powerful than dig but useful for quick lookups and when dig isn’t available.

Basic Usage

# Simple lookup
$ nslookup example.com
Server:         192.168.1.1
Address:        192.168.1.1#53

Non-authoritative answer:
Name:   example.com
Address: 93.184.216.34

# Query a specific server
$ nslookup example.com 8.8.8.8

# Query a specific record type
$ nslookup -type=MX example.com
$ nslookup -type=TXT example.com
$ nslookup -type=NS example.com

# Reverse lookup
$ nslookup 93.184.216.34

Interactive Mode

$ nslookup
> set type=MX
> example.com
Server:         192.168.1.1
Address:        192.168.1.1#53

example.com     mail exchanger = 10 mail.example.com.
> set type=TXT
> example.com
example.com     text = "v=spf1 -all"
> exit

nslookup vs dig

Feature dig nslookup
Trace resolution +trace
DNSSEC checking +dnssec
Output control ✅ Extensive Limited
Available on Windows ❌ (needs install) ✅ Built-in
Response detail Full DNS response Simplified

General recommendation: Use dig when available. Fall back to nslookup on Windows or for quick checks.

drill — DNSSEC-Aware Debugging

drill is part of the ldns library and shines when debugging DNSSEC:

# Basic lookup (similar to dig)
$ drill example.com

# Trace resolution
$ drill -T example.com

# DNSSEC trace (validates the full chain of trust)
$ drill -S example.com
;; Number of trusted keys: 1
;; Chasing: example.com. A
DNSSEC Trust tree:
example.com. (A)
|---example.com. (DNSKEY keytag: 31406 alg: 13 flags: 256)
    |---example.com. (DS keytag: 31406 digest type: 2)
        |---com. (DNSKEY keytag: 30909 alg: 8 flags: 256)
            |---com. (DS keytag: 30909 digest type: 2)
                |---. (DNSKEY keytag: 20326 alg: 8 flags: 257)
;; Chase successful

The -S flag is invaluable for DNSSEC debugging. It shows the entire chain of trust from root to your domain, and tells you exactly where a broken link exists if validation fails.

dog — Modern and Colorful

dog is a newer DNS client written in Rust. It has sane defaults, colorized output, and supports modern protocols:

# Install (macOS)
$ brew install dog

# Basic lookup (colorized by default)
$ dog example.com
A example.com. 5m00s   93.184.216.34

# Multiple record types at once
$ dog example.com A AAAA MX NS

# Query over DNS-over-HTTPS
$ dog example.com --https @https://dns.google/dns-query

# Query over DNS-over-TLS
$ dog example.com --tls @dns.google

# JSON output (great for scripting)
$ dog example.com --json

dog is particularly useful for quickly checking DNS-over-HTTPS (DoH) and DNS-over-TLS (DoT) configurations — something dig can’t do natively.

Online Tools

When command-line tools aren’t enough (or you want a second opinion):

Google Public DNS Toolbox

https://dns.google/

Enter a domain and record type. Shows results from Google’s perspective, including DNSSEC validation status. Particularly useful for checking if Google’s resolvers see your changes.

MXToolbox

https://mxtoolbox.com/

The go-to for email DNS debugging. Tests MX records, SPF, DKIM, DMARC, blacklists, and more. Their “SuperTool” runs comprehensive diagnostics in one click.

DNSViz

https://dnsviz.net/

Visual DNSSEC debugging. Renders the full DNSSEC trust chain as an interactive graph. If your DNSSEC is broken, DNSViz will show you exactly where and why.

intoDNS

https://intodns.com/

Comprehensive health check of your domain’s DNS. Tests for common misconfigurations, checks all nameservers for consistency, and validates SOA records.

whatsmydns.net

https://www.whatsmydns.net/

Shows your DNS records from multiple resolver locations worldwide. Essential for checking propagation after making changes.

Common Debugging Scenarios

Scenario 1: “My site isn’t loading after DNS changes”

# Step 1: Check what your resolver sees
$ dig mysite.com +short
# (empty? old IP? correct IP?)

# Step 2: Check authoritative nameserver directly
$ dig mysite.com NS +short
ns1.cloudflare.com.
ns2.cloudflare.com.

$ dig mysite.com @ns1.cloudflare.com +short
198.51.100.50    # ← This is the source of truth

# Step 3: If resolver differs from authoritative, it's a caching issue
# Wait for TTL to expire, or flush your local cache:
# macOS:
$ sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder
# Linux (systemd-resolved):
$ sudo systemd-resolve --flush-caches
# Windows:
# ipconfig /flushdns

Scenario 2: “Email is going to spam”

# Check all email-related DNS
$ dig example.com MX +short
$ dig example.com TXT +short | grep -i spf
$ dig selector._domainkey.example.com TXT +short
$ dig _dmarc.example.com TXT +short

# If any are missing, that's your problem.
# Use MXToolbox for a comprehensive email health check.

Scenario 3: “Subdomain works, root domain doesn’t”

# Check both
$ dig example.com +short        # Nothing? Missing A record at root
$ dig www.example.com +short    # Works? CNAME probably set correctly

# The root domain needs an A record (or ALIAS/ANAME)
# A CNAME at the root is invalid — check Chapter 1

Scenario 4: “DNSSEC validation failure”

# Check DNSSEC status
$ dig example.com +dnssec +short
# Look for RRSIG records

# Full chain validation
$ drill -S example.com
# Look for "Bogus" in the output

# Visual check
# Visit https://dnsviz.net/d/example.com/dnssec/

Scenario 5: “DNS works on my machine but not on production”

# Check what resolver production is using
$ cat /etc/resolv.conf    # On the production server

# Query the same resolver from your machine
$ dig mysite.com @<production-resolver-ip>

# Check if there's a firewall blocking DNS (port 53)
$ nc -zv 8.8.8.8 53

Building a Debugging Workflow

When something goes wrong, follow this systematic approach:

  1. Identify what’s failing — Name resolution? Specific record type? Specific resolver?
  2. Check the authoritative sourcedig domain @authoritative-ns — is the record correct at the source?
  3. Check your resolverdig domain — does your resolver agree? If not, it’s a caching or propagation issue
  4. Check the delegation chaindig domain +trace — is delegation intact from root to your nameservers?
  5. Check from multiple locations — Use whatsmydns.net or query multiple public resolvers
  6. Check TTLs — Low TTL? Change should propagate quickly. High TTL? You might be waiting a while.

Key Takeaways

  • dig is the primary tool — learn +short, +trace, +noall +answer, and +dnssec
  • nslookup is your fallback on Windows and for quick interactive queries
  • drill -S is essential for DNSSEC chain-of-trust debugging
  • dog adds DoH/DoT support and modern UX
  • Always check the authoritative nameserver first — it’s the source of truth
  • Systematic debugging beats random troubleshooting: authoritative → resolver → delegation → global