
What Do NXDOMAIN, SERVFAIL, and REFUSED Mean in DNS Responses?
Every DNS response carries a small number in its header called the response code, or RCODE. Most of the time it's zero, meaning everything worked, and nobody notices it. When something breaks, though, that code is the single most useful clue you have. NXDOMAIN, SERVFAIL, and REFUSED look similar in an error message, but they point at completely different problems with completely different fixes.
This article explains what each response code actually means at the protocol level, the common causes behind each one, how to reproduce and diagnose them with dig, how Extended DNS Errors add detail, and how to handle them correctly in application code. For a general troubleshooting workflow beyond response codes, see how to troubleshoot DNS issues.
Where Response Codes Come From
A DNS response header contains a 4-bit RCODE field defined in RFC 1035, extended to 12 bits by EDNS. You can see it in the status: field of any dig output:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 18032
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1
The codes you'll actually encounter:
| RCODE | Name | Meaning |
|---|---|---|
| 0 | NOERROR | The query succeeded (the answer may still be empty) |
| 1 | FORMERR | The server couldn't parse the query |
| 2 | SERVFAIL | The server failed to complete the query |
| 3 | NXDOMAIN | The queried name does not exist |
| 4 | NOTIMP | The server doesn't support this kind of query |
| 5 | REFUSED | The server refuses to answer for policy reasons |
There's also a common non-code: NODATA, which is NOERROR with an empty answer section. It means the name exists but has no records of the requested type. We'll come back to it, because it's frequently confused with NXDOMAIN.
If you need a refresher on reading the full dig output, the dig command guide walks through every section.
NXDOMAIN: The Name Does Not Exist
NXDOMAIN ("non-existent domain") is an authoritative statement that the queried name doesn't exist in the DNS, for any record type. It's a definitive negative answer, not a failure.
dig doesnotexist.example.com +noall +comments +authority
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 51210
;; AUTHORITY SECTION:
example.com. 900 IN SOA ns1.example.com. hostmaster.example.com. 2026100101 7200 3600 1209600 900
The SOA record in the authority section tells you which zone issued the denial. Its last field, combined with the SOA record's own TTL, controls how long resolvers cache the "doesn't exist" result, a behavior explained in negative caching in DNS.
Common causes of NXDOMAIN
- A typo. In the hostname, or in the record you created at your DNS host (
ww.example.com, or a record namedwww.example.com.example.combecause the panel appended the zone name). - The record was never created. Very common for subdomains like
apiorstagingafter a migration. - The domain has expired or been suspended. The registry removes the delegation, so the TLD servers return NXDOMAIN for the whole domain.
- The domain isn't delegated yet. A brand-new registration whose nameservers haven't been set, or an unfinished nameserver change.
- A cached negative answer. You created the record a minute ago, but a resolver cached NXDOMAIN when you checked it earlier and will keep returning it until the negative TTL expires.
- DNS filtering. Some filtering resolvers return NXDOMAIN for blocked domains. See what DNS filtering is.
Diagnosing NXDOMAIN
# 1. Does the domain itself exist and have a delegation?
dig example.com NS +short
# 2. Which zone issued the NXDOMAIN?
dig www.example.com +noall +comments +authority
# 3. Does the authoritative server agree?
dig @ns1.example.com www.example.com +norecurse +noall +comments +answer
If step 1 returns nothing, the problem is at the registrar or registry: expiry, missing nameservers, or a hold status. If the authoritative server returns an answer but your resolver says NXDOMAIN, you're looking at a cached negative answer. If the authoritative server also says NXDOMAIN, the record genuinely doesn't exist in the zone.
In browsers, NXDOMAIN surfaces as Chrome's DNS_PROBE_FINISHED_NXDOMAIN page. The user-side fixes for that specific error are covered in the DNS_PROBE_FINISHED_NXDOMAIN guide.
NODATA: The Name Exists, the Type Doesn't
dig example.com AAAA +noall +comments +answer
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 2203
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1
NOERROR with ANSWER: 0 means the name exists, but has no AAAA record. This matters because the fixes differ: NXDOMAIN means create the name; NODATA means add the missing record type. It's also why an empty dig +short result is ambiguous. Always check the status field before concluding a name doesn't exist.
SERVFAIL: The Resolver Couldn't Get an Answer
SERVFAIL means the server tried to answer and failed. Unlike NXDOMAIN, it says nothing about whether the name exists. It's a statement about the resolution process: the resolver couldn't obtain a trustworthy answer.
You'll almost always receive SERVFAIL from a recursive resolver, reporting that something went wrong while it talked to authoritative servers on your behalf.
Common causes of SERVFAIL
- DNSSEC validation failure. The most common cause on modern validating resolvers like 1.1.1.1, 8.8.8.8, and 9.9.9.9. Expired signatures, a DS record at the registrar that doesn't match the zone's keys, or a botched DNS host migration with DNSSEC enabled. See what DNSSEC is.
- Lame delegation. The registry delegates the domain to nameservers that don't answer for the zone, or that answer with REFUSED.
- All authoritative servers are unreachable. An outage at the DNS host, a firewall blocking port 53, or nameserver IPs (glue) pointing to the wrong place.
- Broken zone data on the authoritative server. For example, a zone that failed to load after a syntax error, so the server returns SERVFAIL for every name in it.
- Resolver-side problems. The resolver itself is overloaded, misconfigured, or can't reach the internet.
Diagnosing SERVFAIL
The first test is whether DNSSEC is involved. The +cd (checking disabled) flag asks the resolver to skip validation:
dig example.com A
dig example.com A +cd
If the normal query returns SERVFAIL and the +cd query returns an answer, the zone's DNSSEC is broken. Compare the DS record at the parent with the DNSKEY records in the zone:
dig example.com DS +short
dig example.com DNSKEY +multiline
delv example.com A
delv performs full DNSSEC validation locally and prints a specific reason for failure, such as an expired RRSIG or no matching key.
If +cd still fails, it's a reachability or delegation problem. Query each authoritative server directly:
for ns in $(dig @a.gtld-servers.net example.com NS +norecurse | awk '$4=="NS" {print $5}'); do
echo "== $ns"
dig @"$ns" example.com SOA +norecurse +time=3 +tries=1 +noall +comments | grep status
done
This takes the nameservers from the .com TLD's delegation and asks each one for the zone's SOA. Any server that times out or doesn't return NOERROR with the aa flag is a likely cause. dig example.com +trace shows the same thing hop by hop.
REFUSED: The Server Won't Answer
REFUSED means the server received and understood the query but declines to answer it as a matter of policy. It's a deliberate "no," not a failure.
Common causes of REFUSED
- Asking an authoritative server about a zone it doesn't host. For example, querying your DNS host's nameserver for a domain that isn't in your account. Many authoritative servers answer REFUSED rather than referring you elsewhere.
- Recursion not permitted. You sent a recursive query to a resolver that only serves its own network, such as a company resolver queried from outside, or an authoritative-only server.
- Access control lists. BIND's
allow-queryorallow-recursion, or similar settings in other servers, exclude your IP address. - Zone transfer attempts. An AXFR request from an IP that isn't on the transfer allowlist is refused, which is correct and expected.
- Rate limiting or policy blocks. Some providers refuse queries that match abuse patterns.
Diagnosing REFUSED
# Is this server authoritative for the zone at all?
dig @ns1.example-dns.net example.com SOA +norecurse
# Does it offer recursion to you?
dig @192.0.2.53 example.org A
If an authoritative server returns REFUSED for your domain, the zone isn't configured on that server: perhaps it was deleted, never added to the account, or the delegation points at the wrong provider. If a resolver returns REFUSED, check its recursion ACL. In BIND, that looks like:
// named.conf
acl "trusted" { 192.0.2.0/24; 198.51.100.0/24; localhost; };
options {
recursion yes;
allow-recursion { trusted; };
allow-query-cache { trusted; };
};
Queries from addresses outside the trusted ACL receive REFUSED. After editing, validate with named-checkconf and apply with rndc reconfig. Refusing recursion to the whole internet is the right default, since open resolvers are abused for DNS amplification attacks.
Extended DNS Errors: The Reason Behind the Code
A single SERVFAIL code covers a dozen different failure modes, which made diagnosis painful. Extended DNS Errors (EDE), defined in RFC 8914, let a resolver attach a specific reason code and optional text to any response. Recent dig versions display them in the OPT pseudosection:
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; EDE: 7 (Signature Expired)
Some common EDE codes:
| EDE | Meaning |
|---|---|
| 3 | Stale Answer: served from expired cache because upstream failed |
| 6 | DNSSEC Bogus: validation failed |
| 7 | Signature Expired |
| 9 | DNSKEY Missing |
| 15 | Blocked: blocked by the resolver operator's policy |
| 17 | Filtered: filtered at the client's request |
| 18 | Prohibited: the client isn't allowed to query this server |
| 20 | Not Authoritative |
| 22 | No Reachable Authority: no authoritative server responded |
| 23 | Network Error |
Major public resolvers including Cloudflare's 1.1.1.1 and Google Public DNS return EDE codes. When you're troubleshooting a SERVFAIL, querying one of them with a current dig often tells you the exact cause in a single line.
Handling Response Codes in Code
Applications should treat these codes differently. NXDOMAIN is a definitive answer; SERVFAIL and timeouts are transient and may succeed on retry; REFUSED is a configuration problem that retrying won't fix.
Python (dnspython)
import dns.resolver
def lookup(name: str, rdtype: str = "A") -> str:
try:
answer = dns.resolver.resolve(name, rdtype)
return "OK: " + ", ".join(r.to_text() for r in answer)
except dns.resolver.NXDOMAIN:
return "NXDOMAIN: the name does not exist"
except dns.resolver.NoAnswer:
return "NODATA: the name exists but has no " + rdtype + " records"
except dns.resolver.NoNameservers as e:
# Raised when every nameserver returned SERVFAIL, REFUSED, or similar
return f"FAILED: no server gave a usable answer ({e})"
except dns.resolver.LifetimeTimeout:
return "TIMEOUT: no response within the lifetime"
for host in ["example.com", "doesnotexist.example.com"]:
print(host, "->", lookup(host))
dnspython maps NXDOMAIN and NODATA to distinct exceptions, and groups SERVFAIL and REFUSED under NoNameservers, whose message includes the codes each server returned.
Node.js
import { resolve4 } from "node:dns/promises";
async function lookup(name) {
try {
return { ok: true, addresses: await resolve4(name) };
} catch (err) {
switch (err.code) {
case "ENOTFOUND":
return { ok: false, reason: "NXDOMAIN" };
case "ENODATA":
return { ok: false, reason: "NODATA" };
case "ESERVFAIL":
return { ok: false, reason: "SERVFAIL", retry: true };
case "EREFUSED":
return { ok: false, reason: "REFUSED" };
case "ETIMEOUT":
return { ok: false, reason: "TIMEOUT", retry: true };
default:
throw err;
}
}
}
console.log(await lookup("example.com"));
console.log(await lookup("doesnotexist.example.com"));
The dns/promises resolver functions send real DNS queries and expose the response code through err.code. Note that dns.lookup(), which uses the OS resolver, behaves differently and reports most failures as ENOTFOUND.
Quick Decision Guide
- NXDOMAIN: check spelling, confirm the record exists at your DNS host, confirm the domain is registered and delegated, and wait out negative caching if you just created the record.
- NODATA: the name is fine; add the missing record type.
- SERVFAIL: test with
+cdfor DNSSEC, then query each authoritative nameserver directly for reachability and lame delegation. - REFUSED: confirm you're asking the right server, that the zone exists on it, and that its ACLs allow your query.
For the most common user-facing errors and their fixes, see common DNS errors and their solutions.
DNS Response Codes FAQ
NXDOMAIN is a definitive answer that the name doesn't exist. SERVFAIL means the resolver couldn't get a valid answer at all, so it says nothing about whether the name exists. NXDOMAIN needs a DNS record fix; SERVFAIL usually points to DNSSEC, delegation, or reachability problems.
A resolver probably cached a negative answer when the name didn't exist yet. It will keep returning NXDOMAIN until the negative caching TTL from the zone's SOA expires. Query the authoritative nameserver directly to confirm the record is published.
No, but DNSSEC is the most common cause on validating resolvers. Run the query with dig's +cd flag; if that works while the normal query fails, DNSSEC is the problem. Otherwise check nameserver reachability and delegation.
The server isn't willing to answer that query, usually because the zone isn't configured on it or because an access control list excludes your IP. Confirm the zone exists in your DNS host account and that the delegation points to the right provider.
No. NOERROR with an empty answer, often called NODATA, means the name exists but has no records of the requested type. NXDOMAIN means the name doesn't exist at all.
Extended DNS Errors, defined in RFC 8914, are reason codes that resolvers attach to responses to explain failures, such as Signature Expired or No Reachable Authority. Recent versions of dig display them in the OPT pseudosection.
A limited retry with backoff is reasonable, since SERVFAIL can be transient. Don't retry NXDOMAIN or REFUSED aggressively, because those indicate a missing record or a policy decision that won't change in seconds.
The resolvers may differ in DNSSEC validation, cache state, or network path to your nameservers. A non-validating resolver will answer for a zone with broken DNSSEC, while a validating one returns SERVFAIL.
Conclusion
The response code is the first thing to look at when a DNS lookup goes wrong, because it tells you which class of problem you're dealing with before you start guessing. NXDOMAIN means the name isn't there, so look at the record, the registration, and negative caching. SERVFAIL means resolution broke along the way, so check DNSSEC with +cd and test every authoritative nameserver. REFUSED means a server deliberately said no, so check that you're asking the right server and that its access rules allow you.
Add NODATA to that list, read Extended DNS Errors when a resolver provides them, and handle each case distinctly in your code. With those habits, a cryptic resolution error turns into a precise diagnosis within a few commands.
These references define the response codes and extensions discussed above:
- RFC 1035: Domain Names - Implementation and Specification — defines the DNS header and the original RCODE values.
- RFC 2308: Negative Caching of DNS Queries (DNS NCACHE) — specifies how NXDOMAIN and NODATA answers are cached.
- RFC 8914: Extended DNS Errors — defines the EDE codes that explain why a query failed.
- IANA: Domain Name System (DNS) Parameters — the registry of all RCODE and EDE values.
- Node.js: DNS module documentation — lists the error codes returned by the DNS resolver functions.


