← blog · October 30, 2026

Changing DNS Records and Providers Without Downtime: TTL Ordering, Negative Caching, NS Cutover and DNSSEC

Lowering the TTL before the change, negative caching of missing names, running two providers side by side because of the parent NS TTL, DS ordering with DNSSEC, and the connection pools, proxies and runtime caches that never look at DNS again.

Moving a service to a new server, a new load balancer or a new DNS provider often looks like it comes down to editing one DNS record. The record changes, the dashboard says "saved", and for the next few hours some users reach the old address, some reach the new one, and some reach nothing at all. DNS is not a database. It is a system of caches spread across the internet, and while you control the record, every cache decides on its own clock when it will notice. A migration without downtime is mostly about managing those clocks ahead of time.

Lower the TTL before the change, not with it

A record's TTL tells a resolver how long it may keep the answer. If a record has a TTL of 86400 and you change it, a resolver that asked one minute earlier is entitled to serve the old answer for a full day.

The order that works:

  1. Find the record's current TTL.
  2. Lower it to something short, such as 60 or 300 seconds.
  3. Wait at least the old TTL. The short TTL only takes effect once the answers cached under the long one have expired.
  4. Change the record's value.
  5. Once the cutover is verified, raise the TTL back to its normal value.

The most common mistake is lowering the TTL and changing the value in the same edit. That buys nothing, because the cached old answer keeps living under the old TTL.

Leaving a short TTL in place permanently is not free either. Every lookup travels to your authoritative servers, first-connection latency goes up, and if your authoritative servers are briefly unreachable, caches can no longer cover for them. For records that rarely change, a TTL of a few hours to a day is a healthy default.

To see what the authoritative servers say without any cache in between, ask them directly:

dig +short NS example.com
dig +norecurse @ns1.example.net app.example.com A
dig @1.1.1.1 app.example.com A

The first command lists the authoritative servers, the second shows their current answer, and the third shows what a public resolver currently has cached, along with the time it has left. If the TTL column in the third answer goes down on every query, you are looking at a cached copy.

A missing record gets cached too

If you are adding a new hostname and someone queries it before the record exists, the answer is "no such name", and that answer is cached as well. The negative caching period comes from the zone's SOA record: resolvers use the smaller of the SOA record's own TTL and the minimum field at the end of the SOA.

This is the classic trap of a cutover that runs in the wrong order. A deployment script probes the new name before the record is created, a health check resolves it, a resolver holds on to the NXDOMAIN for hours, and some users still cannot resolve the name after the record exists. The fix is simple: create the record first, then start anything that uses the name. Know your zone's SOA minimum, too. If it is several hours, one query at the wrong moment costs you several hours.

dig +short SOA example.com

Changing providers is a different job

Changing a record's value and moving the zone to another DNS provider are not the same task. In the second case what changes is the NS records in the parent zone, and you do not control their TTL. For common generic TLDs the parent-side NS TTL is around two days, and the registry sets it.

So the safe way to switch providers is to have both providers serve identical content for a while:

  1. Build the full zone at the new provider. Compare every record one by one, especially MX, TXT and verification records.
  2. Query the new provider's authoritative servers directly to confirm the content.
  3. Change the NS records at your registrar.
  4. Keep the old provider running for at least the parent NS TTL, preferably a few days longer. During that window, apply every change to both sides.

Shutting the old provider down right after the NS change means that, for any resolver still holding the old NS records, your entire zone simply disappears.

With DNSSEC, ordering matters even more

If the zone is signed with DNSSEC, the parent zone holds a DS record that points at your key. The new provider signs the zone with its own key, and if the DS record still points at the old one, every validating resolver returns SERVFAIL for your zone. That is not degraded service, it is a full outage, and a team that tests through a non-validating resolver will not see it.

There are two safe paths. The simple one is to remove the DS record first, wait out the DS TTL, move the zone unsigned, and then publish the DS record for the new key. The zone goes without DNSSEC protection for that window, but nothing breaks. The other is the multi-signer model, where each provider publishes the other's keys. Not every provider supports it, and when misconfigured it produces exactly the same SERVFAIL. For most teams the first path is enough.

After the move, check through a validating resolver. If the ad flag shows up in the dig output, the answer was validated.

Clients that ignore DNS

Even with DNS set up correctly, some clients will not see the new address within the TTL, because resolution is cached inside the application as well, not just in the resolver.

Long-lived connections. Connection pools, HTTP keepalive, database and message queue clients resolve a name once and reuse that address for as long as the connection stays open. A DNS change does not close those connections. Keep the old server running until open connections drain, and decide when to shut it down by watching its connection count, not the clock.

Reverse proxies. nginx resolves a hostname written literally in proxy_pass when the configuration is loaded and keeps that address until the next reload. If you need re-resolution, define a resolver and pass the name through a variable; newer releases also offer a resolve parameter on server lines inside an upstream block. Check your proxy's documentation for its actual behavior instead of guessing the default.

Runtime caches. The JVM caches successful lookups according to the networkaddress.cache.ttl security property, independently of the record's TTL. Containers and hosts may also run a local caching resolver. Before a migration, find out which layers in your own clients hold a cache.

Resolvers that raise short TTLs. Some resolvers are configured to raise very short TTLs to a floor. A 60 second TTL does not mean everyone switches within 60 seconds, so your plan should tolerate a tail of several minutes.

Small traps that come up often

You cannot put a CNAME at the zone apex, the bare domain, because a CNAME cannot coexist with other records at the same name and the apex always has SOA and NS. If you want to point it at a load balancer's hostname, use your provider's ALIAS or CNAME flattening feature rather than forcing a record that cannot exist.

If you use zone transfers to secondary servers, a change made without incrementing the SOA serial never reaches the secondaries. Query every authoritative server individually and confirm they all return the same answer.

Do not hand the old IP address to another customer or service right away. Cached answers and long-lived connections will keep sending traffic there for a while, and reusing the address sends that traffic, and sometimes session cookies, to the wrong place.

When not to migrate through DNS

DNS is the wrong tool for a cutover that must be reversible within seconds. Rollback goes through the same caches: reverting the record takes minutes even with a short TTL, and it does nothing to long-lived connections. If you need to shift traffic gradually or roll back instantly, keep the address fixed and do the switch on the load balancer behind it. Use DNS for cases where the address genuinely changes and a tail of a few minutes is acceptable.