DNS Caching: How It Speeds Browsing and When It Breaks Down

Web pages feel instant when name resolution is instant. DNS caching is what makes that happen by avoiding round-trips to authoritative servers on every click. It lives at several layers—your browser, the operating system, the recursive resolver you use, and sometimes at forwarders on your network. When all of these obey time-to-live (TTL) correctly, you get fast and consistent answers.
But caches are opinionated. They keep answers until TTLs expire, and different products add guardrails like minimum or maximum TTLs, “serve stale” behaviors, or local prefetching. Those knobs improve resilience, yet they can also make a simple record change look “stuck.” If you’ve ever changed an A record and some users see the new site while others don’t, you have felt independent caches aging out on their own clocks—not a mystical global propagation wave.
This guide explains how DNS caching works, what TTLs really control, why negative answers are cached differently, and how to fix stale records, poisoning, and hard-to-debug slowdowns without cargo-cult steps that mask the root cause.
What DNS Caches, Where, and Why It’s Fast
Caches exist at four common layers: the browser (a small host resolver cache), the operating system (for example, Windows DNS Client service or a local stub resolver), the recursive resolver (ISP, enterprise, or public anycast services), and optional forwarders you run on premises. A cache serves an answer immediately if it has a fresh copy of the resource record set (RRset). Each RRset in the cache carries its own countdown timer that starts from the authoritative TTL.
Resolver Behavior, TTLs, and Negative Caching
TTLs are per-RRset, not per-name—a CNAME RRset and the A or AAAA RRsets it references can have different TTLs and are cached independently. That’s why a CNAME can expire while the address it points to is still fresh in cache. Negative answers are special: when a name doesn’t exist (NXDOMAIN) or a type is missing (NODATA), resolvers cache the non-existence using the zone’s SOA parameters; in practice, implementations derive the negative cache lifetime from the SOA’s designated negative TTL (commonly the MINIMUM field) and often cap it by the SOA record’s TTL so failures don’t linger too long.
Resolver TTL Floors and Ceilings
Some resolvers let operators clamp TTLs. A floor (“min TTL”) ensures popular answers survive brief outages; a ceiling (“max TTL”) prevents week-long staleness if an authority publishes huge values. If you operate a resolver, set conservative bounds and document them—otherwise application teams will be confused when their 30-second change still lives for 300 seconds.
IPv4, IPv6, and Address Selection
When a hostname has both AAAA and A records, clients often query both and race connections to whichever works first, typically giving a slight preference to IPv6. That racing hides partial network problems, but it also means you will see two separate cached RRsets with independent TTLs. If you shorten one TTL and not the other, user paths can swing between address families during a rollout.
When Caches Bite: Stale Data, Poisoning, and Slowdowns
DNS caching can fail you in three recognizable ways: stale data that hangs around longer than planned, corrupted data from poisoning or on-path tampering, and latent lookups that surface only when hot entries expire. Knowing which symptom you’re facing helps you choose between waiting out TTLs, flushing specific layers, or hardening the resolver and zone.
“Stuck” Answers and the Propagation Myth
Once a resolver has cached an RRset, it will keep serving that data until the TTL reaches zero. Different resolvers are on different clocks and may sit in different anycast locations, so they don’t age out in sync. Some resolvers optionally “serve stale” for a brief window when authorities are unreachable to improve resiliency—good for uptime, surprising during a change window.
Cache Poisoning and How Resolvers Defend
Classic poisoning forges a response to land a fake RRset in cache. Modern resolvers raise the bar with source-port randomization, strong query IDs, case-randomization in query names (the “0x20” trick), bailiwick checking to reject out-of-zone glue, and—most effectively—validation of signed zones with DNSSEC. If you run a resolver, make sure these defenses are on; if you publish DNS, sign your zones so validating resolvers can reject tampered data.
Slow Lookups You Don’t Expect
Slow resolution is usually a timeout somewhere: an unreachable authoritative nameserver, oversized DNSSEC responses getting dropped when fragments are blocked, or referral loops. Because caches hide slowness until an entry expires, problems often appear in bursts as popular names fall out of cache together. Monitor upstream latency and timeouts at the resolver, not just overall success rates.
How to Prove What’s Cached
First, look at what your client sees. Use a resolver explicitly to avoid the local cache: for example, query a known resolver with a command that prints the remaining TTL. Then check the authoritative answer directly to see if what you published matches what caches are aging.
Command Patterns That Work
To bypass caching and see the delegation path, use a trace that walks root → TLD → authority: dig +trace example.com
. To ask a specific resolver and show remaining TTLs in a compact view: dig @resolver-ip example.com A +nocmd +noall +answer +ttlid
. To inspect negative caching parameters, fetch the SOA at the zone apex and read its TTL and MINIMUM (negative TTL) fields: dig example.com SOA +noall +answer
. For browser caches, you can often clear or inspect the host resolver cache using the browser’s internal tools.
Flushing Caches Safely
Only flush what you control and only when you must. On Windows clients, clear the local cache with ipconfig /flushdns
in an elevated shell. On macOS, sending a HUP to mDNSResponder refreshes the local cache (sudo killall -HUP mDNSResponder
); some versions also use dscacheutil -flushcache
. On Linux, the command depends on the component in use (for example, resolvectl flush-caches
for systemd-resolved, or a service-specific command for dnsmasq). On BIND, use rndc flush
; on Unbound, prefer targeted flushes with its control tool. Remember that flushing your own resolver won’t clear upstream public resolvers; those obey their own caches.
Fixes That Actually Work
You’ll avoid most surprises by setting TTLs that match your change cadence, operating your resolver with validation and sensible clamps, and publishing zone data that respects protocol rules and real client behavior.
Pick TTLs for Your Change Cadence
For records you might move during a migration—like apex A/AAAA or CNAMEs to a load balancer—operate with TTLs you can live with in an emergency. Many teams run steady-state at 300–900 seconds and temporarily drop to 30–60 seconds a few hours before a planned cutover, then restore higher values after traffic stabilizes. Extremely low TTLs on NS RRsets are rarely a good idea because they drive higher iterative load.
Pre-Change: Drop, Then Ship
Lower the relevant RRset TTLs well before the change so the older values naturally age out. Avoid last-minute editing of unrelated records; mixed TTLs across a CNAME chain can create asymmetric behavior that looks like flapping.
Steady State: Balance Speed and Stability
Higher TTLs reduce recursive query load and improve resilience when an authority has a hiccup, but they slow down intentional moves. Choose different TTLs by record role: static MX/TXT can be high; edge A/AAAA and CNAMEs should be moderate; failover records should be short enough to meet your recovery objectives.
Operate Your Resolver Like Production
If you run a recursive service, enable DNSSEC validation, set reasonable min/max TTL clamps, consider prefetch and serve-stale for resilience, and monitor upstream timeouts and SERVFAIL rates. Document these settings so application teams understand why a 60-second TTL may live longer locally.
Publish Correct Data
Make sure each zone’s SOA is sane because its parameters govern negative caching. If you use an apex hostname that needs a target normally expressed as CNAME, use your provider’s “alias” or CNAME-flattening feature instead of publishing an illegal apex CNAME. For multi-provider CDNs through a CNAME chain, keep each hop’s TTL aligned with your change cadence.
Go Dual-Stack Deliberately
Test both AAAA and A paths end-to-end before rollout. Expect clients to race addresses and prefer IPv6; ensure the IPv6 target performs as well as IPv4 and has matching health checks and failover. When troubleshooting, examine both RRsets and their TTLs, not just the one you changed.