How to Set TTL Values on DNS Records Without Causing Outages

How to Set TTL Values on DNS Records Without Causing Outages

A DNS record's TTL (time to live) is the number of seconds a resolver is allowed to cache that record before it must ask the authoritative nameserver again. It is not a setting on your web server or your load balancer; it lives in the zone file or DNS API entry for each record, and it is the single number that decides how long the old answer keeps being handed out after you change it. Get DNS TTL best practices wrong and you get the classic outage: the change is live on the authoritative server, but a chunk of the internet is still using the previous address.

The reason is caching all the way down the chain. When a recursive resolver looks up www.example.com, it asks your authoritative server and gets back an answer with a TTL attached. It stores that answer and serves it to everyone who asks until the TTL expires. Your own operating system, your browser, and any intermediate forwarder may cache it too. So the TTL you set today governs how stale your data can be tomorrow.

What the TTL Actually Controls in the Protocol

TTL is a field in the resource record itself, not in the query. An answer looks roughly like this on the wire and in dig output:

$ dig www.example.com A

;; ANSWER SECTION:
www.example.com.  3600  IN  A  203.0.113.10

That 3600 is the number of seconds the resolver may keep this answer. Every record type carries its own TTL: A, AAAA, CNAME, MX, TXT, NS. You can give different records different values. A common setup is a long TTL on stable records like MX and a short one on anything you plan to move.

In a BIND zone file the value is the fourth column, and the file often starts with a default:

$TTL 3600
@   IN  SOA ns1.example.com. hostmaster.example.com. (
        2024010101 ; serial
        7200       ; refresh
        3600       ; retry
        1209600    ; expire
        3600 )     ; negative TTL
www IN  A   203.0.113.10
api IN  A   203.0.113.11

Note the last field on the SOA line. That is the negative caching TTL, and it controls how long a resolver remembers that a name does not exist. It matters more than people expect: if you query a name before you create it, and the negative answer is cached, the name stays "missing" for that resolver until the negative TTL runs out, even after you publish the record.

On managed DNS providers you do not edit a zone file; you set the TTL per record in their interface or API, and the provider writes it into the zone it serves. The mechanics are identical. The value still ends up in the answer, and resolvers still honour it.

DNS TTL Best Practices Before a Migration

The core rule is that you must lower the TTL before you need the change to propagate, and you must wait out the old TTL before making the change. These are two separate waits and people routinely collapse them into one.

Suppose your records currently carry a TTL of a day. You decide to move the site to a new address. If you change the address now, resolvers that cached the old answer will keep sending traffic to the old address for up to a day. Lowering the TTL now does not help those resolvers, because they already hold an answer stamped with the old, long TTL. The new short TTL only takes effect for queries that arrive after the change.

So the sequence is: first, lower the TTL on the records you are about to touch and publish that change. Then wait for the previous TTL to elapse, so every resolver has had to come back and pick up the short value. Only then change the address. After the migration is confirmed good, raise the TTL back up, again after waiting out the short value.

How low should the pre migration TTL go? Low enough that a mistake is corrected quickly, high enough that you are not hammering your authoritative servers. A few minutes is a reasonable working value for a cutover window. Setting it to a handful of seconds is usually pointless, because many resolvers enforce a floor and will not cache below it regardless of what you publish.

Two other things are worth checking before you start. Confirm that every record in the chain has the short TTL, not just the one you remember. If www is a CNAME pointing at another name, that target has its own TTL. And check whether anything in front of your authoritative servers, such as a secondary or a hidden primary, is serving a different zone copy with different values.

Verifying What Resolvers Actually See

Do not trust the control panel. Query the authoritative server directly and then query a public resolver, and compare. Asking the authoritative server bypasses caches and shows you the truth you published:

$ dig @ns1.example.com www.example.com A +noall +answer
www.example.com.  300  IN  A  203.0.113.10

$ dig @1.1.1.1 www.example.com A +noall +answer
www.example.com.  300  IN  A  203.0.113.10

If the second query returns the old address with a long TTL remaining, that cache has not caught up yet and you wait. If it returns the new address, that resolver is current. Run the check against several resolvers in different networks, because caches expire independently and there is no global "propagated" flag to consult.

To watch a specific record expire, query it repeatedly and read the countdown. The TTL in the answer decreases as the cache ages, then resets when the resolver fetches a fresh copy. That reset is the moment your change becomes visible to that resolver.

When you raise the TTL back after a migration, apply the same patience in reverse. Raising it too early means some resolvers still hold the short lived answer and will refetch sooner than you intended, which is harmless. The real hazard is raising it and then discovering a problem you need to fix, because now the fix has to wait out the long TTL you just published. Confirm the new setup is stable for a full day or more before you extend the TTL.

Common Ways People Cause Their Own Outage

Lowering the TTL at the same moment as the address change is the most frequent mistake. The two actions look like one step, but the first only helps future queries, and the caches you care about already answered before it took effect.

Raising the TTL immediately after the change is the second. You have not yet waited out the short value, so some resolvers still have old data, and you have just made the next correction slow.

Forgetting the negative TTL is the third. If you pre create a name by querying it, or if a monitoring check hits a name before it exists, the nonexistence gets cached for the negative TTL. A long negative TTL turns a small mistake into a long one.

Ignoring the target of a CNAME is the fourth. You lower the TTL on the alias and leave the real record long, and the change still crawls.

Finally, remember that TTL only governs caching. It does not control how fast your authoritative servers accept a zone change, how fast a secondary transfers it, or whether your provider's control plane has actually published it. Verify at the authoritative server first, then work outward.

Next time you plan a change, write the sequence down before you touch anything: which records, what the current TTL is, when you will lower it, how long you will wait, when you will cut over, and when you will raise it again. Then verify with dig against both the authoritative server and a few public resolvers at each step. If you want to practise, pick a record you do not depend on, lower its TTL, watch the countdown in the answer section, and see for yourself how long a cache really holds on.

Related articles

Subscribe to our newsletter

Get the latest hosting tips, performance insights, and industry news.