Added a DNS record but it still says the name doesn't exist? NXDOMAIN, NODATA and negative caching

Why resolvers can keep saying "no such name" after you add a record: NXDOMAIN vs NODATA, the negative TTL from the SOA, the NXDOMAIN cut, and the 5-minute cap on failure caching.

DevelopmentNetworking

You add a record for a new subdomain on the authoritative server. On some networks it shows up at once; on others the answer stays “no such name” for a while. Resolvers don’t only cache records that exist. They also cache the answer that something doesn’t exist. That’s negative caching, and the rules are in RFC 2308. This post is based on RFC 2308, RFC 8020 and RFC 9520 (two of the RFCs that update it, the ones relevant here), and the related RFC 8767. It doesn’t cover the defaults of any particular resolver product.

The basic lookup flow and the TTL of ordinary records are covered in From domain name to IP address: how a DNS lookup works.

Two kinds of “no”

Sections 1 and 2 of RFC 2308 split negative responses into two kinds.

  • NXDOMAIN: the RCODE in the response header is Name Error. The queried name itself doesn’t exist.
  • NODATA: the RCODE is NOERROR, but the answer section has no records of the requested type. The name exists, but has no records of that type. There is no RCODE value for NODATA, so it has to be worked out from the contents of the response.

They are also cached under different keys (RFC 2308 Section 5).

  • NXDOMAIN is cached against <QNAME, QCLASS>. The whole name is remembered as missing, whatever the type.
  • NODATA is cached against <QNAME, QTYPE, QCLASS>. Only that type is missing.

So if you add an AAAA record to a name that already has an A record, the only thing that can still be cached is a NODATA for AAAA; A lookups aren’t affected. If you create a name that didn’t exist before, an NXDOMAIN that someone got by looking it up earlier can block lookups of every type.

The negative TTL comes from the SOA

In an ordinary response, each record in the answer section has its own TTL. A negative response has no answer records, so the TTL has to travel some other way. RFC 2308 Section 3 says that a server authoritative for a zone MUST include the zone’s SOA record in the authority section when it answers NXDOMAIN or NODATA. The TTL of that SOA record is set to the smaller of the SOA’s MINIMUM field and the TTL of the SOA record itself, and that value is how long a resolver may cache the negative answer.

The MINIMUM field used to carry several meanings. RFC 2308 Section 4 deprecates its original meaning, “the minimum TTL of all records in the zone”. For its use as the default TTL of records written without one, it adds the $TTL directive to the master file format instead. It then gives MINIMUM its new meaning: the TTL of negative responses. Despite the name, today the field sets how long negative answers are cached.

A cached negative answer’s TTL counts down like any cached answer, and once it reaches zero the answer MUST NOT be used again (Section 5). When a server answers from a cached negative response, it must attach the SOA with its TTL reduced by the time spent in the cache (Section 6). In the example in Section 10 of RFC 2308, a zone has MINIMUM 1200. The first NXDOMAIN response carries an SOA TTL of 1200, and the same answer served from cache ten minutes later carries 600. Read the SOA TTL a resolver shows you as the time remaining.

Two things follow from this.

  • How long a negative answer stays valid is fixed when the resolver receives it. Lowering MINIMUM later doesn’t shorten entries already cached; they count down from the TTL they arrived with.
  • If you plan to create a new name, the smaller of the zone’s SOA MINIMUM and SOA TTL is the worst-case wait if someone looked the name up beforehand. A resolver with its own cap may hold it for less.

Negative responses that carry no SOA SHOULD NOT be cached (Section 5). Without a TTL counting down, a negative answer could loop between two servers, for example two that list each other as forwarders, with its TTL reset on every pass.

Caps on the resolver side

RFC 2308 Section 5 calls it sensible for a resolver to limit how long it caches negative answers, on the grounds that the protocol supports caching for up to 68 years. The limit should not be greater than the one applied to positive answers, and should preferably be tunable. The same section reports that one to three hours has worked well and would make a sensible default, and that values over a day have been found to cause problems. That is advice from a 1998 document.

The 68-year premise has since changed. RFC 8767 Section 4 (2020) amends the TTL definition in RFC 1035: TTL values with the high-order bit set are interpreted as positive rather than 0, and values SHOULD be capped on the order of days to weeks, with a recommended cap of 604,800 seconds (7 days). The same section says that suggesting 7 days, rather than the 68 years allowed by the full 31 bits in RFC 2181 Section 8, reflects the current practice of major modern resolvers. The cap a given resolver actually uses depends on the product, version and configuration, and is outside the scope of this post.

NXDOMAIN means nothing exists underneath either

RFC 8020 made the meaning of NXDOMAIN explicit. Domain names form a tree, so if a node doesn’t exist, neither does anything in the subtree below it. Section 2 says that when an iterative caching resolver receives an NXDOMAIN, it SHOULD cache it, treat every name at or below that node as unreachable, and answer later queries for such names with NXDOMAIN. This is called the NXDOMAIN cut. Section 3.2 revises the sentence in RFC 2308 Section 5 so that a cached NXDOMAIN can also be returned for queries about descendants of the original QNAME.

The RFC 8020 example: a resolver that asked for the nonexistent foo.example and got NXDOMAIN can answer a following query for bar.foo.example with NXDOMAIN straight away, without sending it to an authoritative server. If the first query had been for bar.foo.example, that NXDOMAIN says nothing about baz.foo.example. Nor may the resolver use the owner name of the accompanying SOA to conclude that a name further up is missing (Appendix A): the SOA marks the apex of the zone, not the closest name that exists.

Here is one way this bites in practice. In the example.com zone, dev.example.com doesn’t exist yet, and someone looks it up. Then you add a record for api.dev.example.com. While the NXDOMAIN for dev.example.com is still cached, a resolver that applies the NXDOMAIN cut can answer NXDOMAIN for api.dev.example.com too, even though nobody had ever queried the new name.

A few qualifications.

  • The rule is SHOULD, not MUST. RFC 8020 Section 6 explains that resolvers whose cache isn’t organised as a tree (a dictionary, for instance) have a reason not to follow it. Section 1 notes that, when the RFC was published in 2016, most known resolvers did not treat a cached nonexistence as proof that no child names exist. Don’t assume the scenario above happens with every resolver.
  • If a resolver already has cached data below the cut, it MAY keep answering with it until that data’s TTL runs out (Section 2).
  • A validating resolver MAY apply the NXDOMAIN cut only when the NXDOMAIN has been validated with DNSSEC (Section 2).
  • For a name that has no records of its own but has names below it (an Empty Non-Terminal, like dev.example.com in the example once the record is added), the correct answer is NODATA, not NXDOMAIN (Section 3.1). Section 5 says authoritative servers that answer such names with NXDOMAIN are wrong and always have been.

Server failures are cached separately

NXDOMAIN and NODATA are cases where the server gave a useful answer: “it doesn’t exist”. RFC 9520 Section 2 states plainly that these are not resolution failures, and defines resolution failure separately: none of the available servers gives a useful answer for a given <name, type, class>. Its examples include SERVFAIL, REFUSED, timeouts and unreachable servers, delegation loops, alias (CNAME) loops, DNSSEC validation failures and FORMERR.

RFC 2308 Section 7 pointed out that these responses have no way to carry a desired TTL. It made caching of server failures and dead servers optional, with a limit of five minutes. RFC 9520 (2023) strengthened this.

  • Resolvers MUST cache resolution failures (Section 3.2). While a cached failure matches an incoming query, the resolver MUST NOT send the corresponding outgoing queries until the entry expires.
  • The cache duration is at least 1 second and at most 5 minutes (Section 3.2). The minimum SHOULD be configurable by the operator, and for persistent failures the duration SHOULD grow with exponential or linear backoff. The RFC gives starting at 5 seconds as an example, nothing more.
  • A resolver may retry a given query to the same server address over the same transport at most twice, so three queries in total (Section 3.1). Retrying at a different server or over a different transport is not ruled out (Sections 2 and 3.1).

In short, “the name doesn’t exist” is cached for a time set by the SOA, and “no server could answer” for between 1 second and 5 minutes, chosen by the resolver. If SERVFAIL lingers briefly after you fix the authoritative server, it may be the second kind, and under the RFC that lasts no more than five minutes.

How serve-stale fits in

RFC 8767 lets a resolver use expired data, as an exception, when it can’t reach the authoritative servers. Section 4 says that an answer from an authoritative server with RCODE NoError or NXDomain and the AA bit set MUST be treated as refreshing the data. Any other RCODE SHOULD be treated as a failure to refresh, leaving the previous state as it was. So after you delete a name, once the authoritative server returns an NXDOMAIN with the AA bit set, a resolver that serves stale data accepts it as a refresh too. Section 6 explains that an NXDomain for a name that used to exist might well be a mistake, but it isn’t treated as an error because there’s no reliable way to tell the operator’s intent.

Before you make the change

  • Look at the SOA MINIMUM and the SOA record’s TTL for the zone where the new name will go. The smaller one is the longest a negative answer for it can be cached.
  • Looking a name up before it’s published can itself leave an NXDOMAIN cached for that long. If you looked it up while its parent name didn’t exist, names below it can be affected too on resolvers that apply the NXDOMAIN cut.
  • Adding a new type to an existing name only affects the NODATA for that type.
  • SERVFAIL and timeouts belong to the resolution-failure cache, not the negative cache, and the RFC caps that at five minutes.

RFCs used

  • RFC 2308 — Negative Caching of DNS Queries (DNS NCACHE) (1998): Section 1 (NXDOMAIN and NODATA terms), Section 2 (forms of negative responses), Section 3 (SOA requirement and TTL for authoritative servers), Section 4 (redefinition of the SOA MINIMUM field, $TTL), Section 5 (cache keys, TTL countdown, responses without SOA, resolver caps), Section 6 (TTL when answering from cache), Section 7 (server failure, dead servers), Section 10 (example).
  • RFC 8020 — NXDOMAIN: There Really Is Nothing Underneath (2016): Section 1 (background), Section 2 (the NXDOMAIN cut rule and its exceptions), Section 3.1 (Empty Non-Terminals get NODATA), Section 3.2 (revision of RFC 2308 Section 5), Sections 5 and 6, Appendix A.
  • RFC 9520 — Negative Caching of DNS Resolution Failures (2023): Section 2 (definition and examples of resolution failure), Section 3.1 (retry limit), Section 3.2 (mandatory failure cache, 1 second to 5 minutes, backoff).
  • RFC 8767 — Serving Stale Data to Improve DNS Resiliency (2020): Section 4 (amended TTL definition and 604,800-second recommended cap, NoError and NXDomain responses count as a refresh), Section 6.

This post covers only what the standards say. A real resolver’s negative-cache cap, whether it applies the NXDOMAIN cut, and how long it caches failures depend on the product, version and configuration, so check the documentation for the resolver you use. Links and content checked October 9, 2026.

Back to the blog