How to check dns ttl
A TTL from a caching resolver is what is left of a countdown, not the value in the zone. Read it with nslookup -debug -type=A example.com 8.8.8.8, and the same query a minute later gives a different number. Ask the zone's own nameserver for the configured value.
Checker offline. Follow the manual steps below, they give the same answer.
Why check this
Run this before you schedule a cutover and before you write any timing into a release plan. The TTL is the only number that says how long a client keeps using the old answer after you change the record. The failure it prevents is the deploy window sized from the wrong number: a team reads 90 from a resolver, plans a two-minute switch, and finds traffic still arriving at the retired host forty minutes later because the zone says 3600.
The second reason is that the TTL you read from a public resolver is an observation about that resolver's cache, not about your zone. Step 3 reads both and shows them disagreeing on the same record, in the same second.
Prerequisites
nslookup -debug. The plain output prints addresses and never a TTL. The debug output prints the full answer section includingttl.- Node 22 for the sampling scripts. Both use
dns.Resolverwith an explicit server, because the operating system resolver on this machine refuses queries. - An authoritative nameserver for the zone. Get one from How to check ns record, or from
nslookup -type=NS example.com 8.8.8.8.
Steps
- Step 1.
Read the TTL of a single answer.
nslookup -debug -type=A example.com 8.8.8.8Got answer: HEADER: opcode = QUERY, id = 2, rcode = NOERROR header flags: response, want recursion, recursion avail. questions = 1, answers = 2, authority records = 0, additional = 0 QUESTIONS: example.com, type = A, class = IN ANSWERS: -> example.com internet address = 104.20.23.154 ttl = 300 (5 mins) -> example.com internet address = 172.66.147.243 ttl = 300 (5 mins) - Step 2.
Ask the same resolver the same question six times, ten seconds apart. Save this as
ttl-watch.jsand runnode ttl-watch.js.const { Resolver } = require('node:dns'); const name = 'example.com'; const pub = new Resolver(); pub.setServers(['8.8.8.8']); const wait = (ms) => new Promise((r) => setTimeout(r, ms)); (async () => { for (let i = 0; i < 6; i += 1) { await new Promise((done) => { pub.resolve4(name, { ttl: true }, (e, a) => { console.log(new Date().toISOString().slice(11, 19) + ' ttl=' + (e ? e.code : a[0].ttl)); done(); }); }); if (i < 5) await wait(10000); } })();20:41:18 ttl=300 20:41:28 ttl=257 20:41:38 ttl=300 20:41:48 ttl=290 20:41:58 ttl=280 20:42:09 ttl=101Six identical queries, fifty seconds, six different numbers, and the sequence goes up as well as down.
8.8.8.8is one address served by many machines, each holding its own copy of the answer with its own age. Each reply is the remainder on whichever machine took the query. - Step 3.
Read the resolver and the zone's own nameserver in one run. Save this as
ttl-compare.jsand runnode ttl-compare.js example.com hera.ns.cloudflare.com.const { Resolver } = require('node:dns'); const [name, authNs] = process.argv.slice(2); const pub = new Resolver(); pub.setServers(['8.8.8.8']); const read = (res, label) => new Promise((done) => { res.resolve4(name, { ttl: true }, (e, a) => { const t = new Date().toISOString().slice(11, 19); console.log(`${t} ${label.padEnd(18)} ${e ? e.code : a.map((v) => `${v.address} ttl=${v.ttl}`).join(' ')}`); done(); }); }); const wait = (ms) => new Promise((r) => setTimeout(r, ms)); (async () => { await read(pub, '8.8.8.8'); await wait(20000); await read(pub, '8.8.8.8'); await wait(20000); await read(pub, '8.8.8.8'); const ip = await new Promise((d) => pub.resolve4(authNs, (e, a) => d(a[0]))); const auth = new Resolver(); auth.setServers([ip]); await read(auth, authNs); })();20:40:26 8.8.8.8 172.66.147.243 ttl=300 104.20.23.154 ttl=300 20:40:46 8.8.8.8 104.20.23.154 ttl=300 172.66.147.243 ttl=300 20:41:06 8.8.8.8 104.20.23.154 ttl=163 172.66.147.243 ttl=163 20:41:06 hera.ns.cloudflare.com 104.20.23.154 ttl=300 172.66.147.243 ttl=300The last two lines are one second apart on the same record. The cache says 163, the zone says 300. 300 is the number to plan against, because it is the longest any resolver can hold this answer.
- Step 4.
Read the same value on Windows without Node.
Resolve-DnsName example.com -Type A -Server 8.8.8.8 | Format-Table Name,Type,TTL,IPAddress -AutoSizeName Type TTL IPAddress ---- ---- --- --------- example.com A 300 104.20.23.154 example.com A 300 172.66.147.243-Serversends the query to the named resolver and bypasses the Windows resolver cache, so the number is the remote cache's remainder. Drop-Serverand the number comes from the local cache instead.
How to read the result
| What you see | What it means | What to do |
| --- | --- | --- |
| The configured maximum, such as ttl = 300 | The resolver had no copy and fetched a fresh one | Treat this as the zone's value, and confirm against the nameserver |
| A smaller number such as 163 | The remainder of a countdown on the machine that answered | Plan against the configured value, never against this |
| The number rises between two reads | A different machine behind the same anycast address replied | Stop treating repeated reads as one cache |
| The authoritative server returns the same number every time | That is the configured TTL. It does not count down | Size the cutover window from it |
| Non-existent domain with no TTL shown | A negative answer, cached under the SOA minimum, not the record TTL | Read the SOA to find how long the absence is held |
Common mistakes
What to check next
- How to check dns propagation: the same countdown seen across several resolvers at once.
- How to check dns cache: the copy on your own machine, which has its own countdown.
- How to check a record of domain: the record these TTLs belong to.
- How to check ns record: where to find the authoritative nameserver step 3 needs.
- How to check DNS lookup time: what a cache miss costs the client when the TTL runs out.
FAQ
How to check dns ttl nslookup shows by default?
It does not show one. Plain nslookup prints names and addresses only. Add -debug and the TTL appears on each record in the answer section, as in step 1. -d2 prints the request packet as well.
How to check dns ttl value in windows?
Resolve-DnsName example.com -Type A -Server 8.8.8.8 has a TTL column, as in step 4. For the copy held on the machine itself, Get-DnsClientCache -Entry example.com prints a TimeToLive that counts down in real time.
How to check dns record ttl for a type other than A?
Change the type and read the same field: nslookup -debug -type=MX example.com 8.8.8.8, or Resolve-DnsName example.com -Type MX. Each record type at a name carries its own TTL, and they are often different.
Which number do I plan a cutover against?
The value an authoritative nameserver returns, because that is the longest any resolver is allowed to hold the answer. Add the time it takes your provider to publish an edit, and treat clients that ignore TTLs as a separate problem.
Verified
Verified by Maks Vernynslookup Windows 11 build 22631node 22.23.2PowerShell 5.1
Each output block is what the command above it printed on that date, on the host named in the step. Figures read from a live site move between runs. Compare the shape of the answer rather than the digits, and see the methodology for how a page is re-verified.
Related on this site
- Checker: dns-records A, AAAA, CNAME, MX, NS, TXT with TTL from two public resolvers, mismatch between resolvers
- DNS migration checklist
- All email and dns checks
intermediate7 minpublished updated Maks Verny