When resolvectl Caches Fail: Quick Steps to Clear Stale DNS Entries Without Restarting NetworkManager

When a host suddenly resolves a domain to an old IP, the first instinct is to restart NetworkManager or reboot the machine. That works, but it’s heavy‑handed and can disrupt services. In a production environment, a brief outage can trigger SLA violations or expose stale data to clients. Below is a concise, hands‑on guide to flushing the systemd‑resolved cache safely, with a focus on security‑aware operators who need minimal downtime.

Why the Cache Persists

systemd‑resolved keeps a local cache of DNS answers to speed up lookups and reduce upstream traffic. The cache is governed by the TTL returned by the authoritative server. If a record’s TTL is long (e.g., 86400 s), the cache will hold the answer until it expires. A mis‑configured or stale record can therefore linger for hours, even days.

In 2025, many distributions shipped a systemd-resolved version that added a --flush-caches flag to resolvectl. That flag was later deprecated in favor of the flush-caches subcommand, which is still available in 2026 releases. Knowing the correct syntax for your distro is key.

Quick‑Check: Is the Cache the Culprit?

# Verify the current DNS resolver
systemd-resolve --status | grep -A 5 'DNS Servers'

# Inspect the cached entry for a specific host
resolvectl query example.com

If the resolvectl query output shows an IP that no longer matches the authoritative zone, you’re dealing with a stale cache.

Step 1: Flush the Global Cache

The simplest command clears all cached records for all interfaces:

sudo resolvectl flush-caches

Trade‑off

  • Pros: Immediate effect, no service interruption.
  • Cons: All cached queries are lost, so the next lookup will hit upstream DNS, adding a small latency spike.

If you’re on a system that still uses the older systemd-resolve, the equivalent is:

sudo systemd-resolve --flush-caches

Both commands are idempotent; running them repeatedly is safe.

Step 2: Targeted Cache Flush (Optional)

When you only need to clear a specific domain, you can use the --cache option:

sudo resolvectl flush-caches example.com

This removes only the cached entries for example.com. It’s useful when you know the problem is isolated to a single host, and you want to keep other cached lookups intact.

Caveat
--cache is not supported on all systemd versions. If the command fails, fall back to the global flush.

Step 3: Verify the Result

resolvectl query example.com

The output should now show the new IP address. If it still shows the old one, the upstream DNS server may still be serving the stale record. In that case, wait for the TTL to expire or contact the authoritative DNS administrator.

Step 4: Harden the Cache Behavior

Stale caches can be a subtle attack vector. An adversary could poison a DNS cache and then wait for the TTL to expire before the cache is refreshed. To mitigate this:

  1. Enable DNSSEC

    sudo resolvectl dnssec-enable yes
    sudo resolvectl dnssec-validation yes
    

    Systemd‑resolved will reject unsigned or invalid records, reducing the risk of cache poisoning.

  2. Reduce Default TTL

    Edit /etc/systemd/resolved.conf and set a lower Cache value (seconds). For example:

    [Resolve]
    Cache=3600
    

    This forces the resolver to re‑query upstream every hour, limiting how long a stale record can persist.

  3. Use a Local DNS Forwarder

    Deploy dnsmasq or unbound as a local forwarder with strict ACLs. These tools can be configured to drop queries from untrusted networks, adding an extra layer of protection.

Step 5: Automate Cache Management (Optional)

If you frequently encounter stale entries, consider a cron job that flushes the cache at a low‑impact time:

# /etc/cron.d/flush-dns-cache
30 3 * * * root resolvectl flush-caches

This runs nightly at 3 AM, a window that typically sees low traffic. Adjust the schedule to match your environment.

Common Pitfalls and Troubleshooting

SymptomLikely CauseFix
resolvectl query still shows old IPCache not flushed (wrong command)Ensure you’re using the correct flush-caches syntax for your systemd version
DNS queries hang after flushNetworkManager not re‑initializing socketsRestart NetworkManager only if the flush fails; otherwise, use systemctl restart systemd-resolved
Stale records persist beyond TTLAuthoritative server still serving old recordVerify the zone file; use dig @<nameserver> example.com to confirm
Security alerts about DNSSEC failuresDNSSEC validation disabled or misconfiguredRe‑enable DNSSEC as shown in Step 4

Real‑World Example: A Homelab Scenario

I run a small media server behind a pfSense router. The router’s DNS cache was holding an old IP for my internal media.local zone after I migrated the server to a new machine. Restarting pfSense was not an option because it also hosts VPN services.

  1. On the media server, I ran sudo resolvectl flush-caches.
  2. Verified with resolvectl query media.local that the new IP appeared.
  3. Added a cron job to flush the cache every 30 minutes, ensuring the server never served stale media URLs to clients.

The result: no downtime, no VPN interruption, and a cleaner DNS environment.

Security Implications

While flushing the cache is a quick fix, it’s also a reminder that DNS is a critical attack surface. By ensuring your resolver validates DNSSEC and by limiting TTLs, you reduce the window an attacker can inject malicious records. Additionally, keeping the resolver’s cache small means fewer stale entries that could be exploited.

Further Reading

See also