DNSSEC fails after KSK-2024 rollover (key 38696)
Lookups ending in SERVFAIL since 11 October 2026? Check whether your resolver trusts root key tag 38696 with the RFC 8509 sentinel test, then fix the anchor.
What broke on 11 October 2026
DNSSEC fails after the root KSK rollover when your validating resolver does not trust KSK-2024. That is the new root key, and its key tag is 38696. Since 11 October 2026 it signs the root zone. Some resolvers still know only the old key, KSK-2017, whose key tag is 20326. Such a resolver cannot check any answer below the root, so its lookups end in SERVFAIL. To fix it, give the resolver the new key from a trusted source. Then make sure the resolver can keep it.
First, the terms. DNSSEC (DNS Security Extensions) adds signatures to DNS answers. A validating resolver checks those signatures along a chain that starts at the root zone. The root KSK (key signing key) is the first link of that chain. The resolver holds its own copy of the key, called a trust anchor. It accepts nothing it cannot connect back to that anchor. If you are new to how DNS resolution works, read that first. SERVFAIL is the DNS response code a resolver returns when it cannot give a usable answer.
IANA (the Internet Assigned Numbers Authority) publishes the timeline on its trust anchors page. KSK-2024 was published in the root zone on 11 January 2025. RFC 5011 is the standard for automatic trust anchor updates. Resolvers that follow it could start trusting the new key on 10 February 2025. RFC 5011 makes a resolver watch a new key for at least 30 days before it trusts it. That is the gap between those two dates. On 11 October 2026 KSK-2024 took over signing. IANA still lists KSK-2017 as a valid trust anchor, but it no longer signs the zone. As of October 2026, IANA has scheduled the revocation of KSK-2017 for 11 January 2027. Its removal from the root zone is scheduled for 22 March 2027.
A missing anchor breaks a lot. Akamai's guidance says a resolver without it "will fail to resolve both signed and unsigned domains, leading to widespread SERVFAIL errors". ICANN describes the same case as total DNS resolution failure. Unsigned names fail too. The proof that a zone has no signatures is itself signed by the zone above it, and that chain also starts at the root key. This guide covers Unbound, BIND, Knot Resolver, PowerDNS Recursor and systemd-resolved. It also covers the Unbound that often sits behind a Pi-hole or AdGuard Home. The commands below need outbound DNS and HTTPS, so run them on your own server.
Is the root key the cause? Triage first
Query a few names you use, and run each query twice. Run it once as normal, and once with +cd. The +cd flag sets the CD (checking disabled) bit. That bit asks the resolver not to perform DNSSEC validation for that query. Replace 127.0.0.1 with the address your resolver listens on.
dig @127.0.0.1 example.com A +noall +comments +answer
dig @127.0.0.1 example.com A +cd +noall +comments +answerRead the status: field in the header comments of each reply. Then match the pattern:
- SERVFAIL for every name, but answers come back with
+cd. The data is reachable, and validation fails everywhere. A missing root trust anchor breaks the whole resolver at once, and the rollover produces exactly this pattern. Go to the checks below. - Some names fail and others resolve. Akamai's triage says: "If some domains resolve normally and others do not, the root key is unlikely to be the cause." The failing names have a problem in their own zone, and the zone owner has to fix it.
- SERVFAIL even with
+cd. You asked the resolver to skip validation, so validation is not the problem. The resolver cannot reach its upstream or the root servers. Check the network path first. For example, check whether port 53 is open between the hosts. If the resolver sits behind a tunnel, see DNS that breaks inside a WireGuard tunnel.
Why does systemd-resolved log no-signature or incompatible-server?
If your server uses systemd-resolved, read its log before you blame the root key:
journalctl -u systemd-resolved -n 200 --no-pager | grep "DNSSEC validation failed"Two kinds of line matter here. These are copied from public bug reports, so your question names will differ:
DNSSEC validation failed for question . IN SOA: incompatible-server
DNSSEC validation failed for question wttr.in IN A: no-signatureBoth strings were reported long before KSK-2024 signed anything. Launchpad bug 1981431 was filed in July 2022. The reporter had turned on DNSSEC on Ubuntu 22.04, and name resolution stopped after some hours. The reported workaround was resolvectl reset-server-features. The no-signature line comes from an Arch Linux forum thread from September 2025. Users lost name resolution after upgrading to systemd 258-2. A moderator explained that upstream behaviour did not change. Arch's package had changed the build-time default.
The resolved.conf manual explains the risk. DNSSEC= takes a boolean or allow-downgrade, and the documented default is allow-downgrade. The manual also says the default is set at compile time, so your distribution can ship a different one. For the setting turned on, the manual warns: "If the DNS server does not properly support DNSSEC all validations will fail." Ubuntu ran into the same problem. Issue 9 of the Ubuntu Server Gazette says Ubuntu planned to turn DNSSEC on by default in 25.10. That caused DNS failures in LXD containers, so DNSSEC became opt-in for that release.
Check which setting your system actually uses:
systemd-analyze cat-config systemd/resolved.conf | grep -i dnssec
resolvectl statusYou may never have set DNSSEC=yes, and the errors may have started right after a systemd upgrade. If so, suspect a changed default before you suspect the rollover. For incompatible-server after DNSSEC was turned on, sudo resolvectl reset-server-features is the workaround from the Launchpad report.
Check 1: is key tag 38696 in the trust anchor file?
ICANN tells operators to look for key tag 38696 in the trust anchor file. Its July 2026 guidance is direct: "System administrators must manually verify their configurations rather than assume automatic updates worked." ICANN lists the usual file names. ISC BIND uses bind.keys. Unbound and PowerDNS Recursor use root.key. Knot Resolver uses root.keys. Packages put these files in different places, so start from the path your own configuration names.
For Unbound, the auto-trust-anchor-file setting names the file. Put the path it prints into a variable, then search the file:
grep -R "auto-trust-anchor-file" /etc/unbound/
ANCHOR=/path/printed/above/root.key
sudo grep 38696 "$ANCHOR"On Debian and Ubuntu, the dns-root-data package can hold another copy of the root anchor that other software reads. Search every file it installs:
dpkg -L dns-root-data | xargs -r sudo grep -ls 38696The command prints the name of each file that contains the key tag. No file names in the output means no file from that package has it. If the package is not installed, dpkg reports an error instead.
For Knot Resolver, find the trust anchor file in your configuration and search it the same way. ICANN calls it root.keys, but the example in the Knot Resolver docs uses root.key. Trust your own config over either name.
For BIND, the documentation says the root trust anchor "is provided as part of BIND". It is kept current with RFC 5011. BIND tracks that state in a managed-keys database. sudo rndc managed-keys sync writes the database to disk. The file is managed-keys.bind, or viewname.mkeys when you use views. Where that file lives depends on your named.conf.
For PowerDNS Recursor, the root key is built into the program. A file only matters if you set dnssec.trustanchorfile, and a root anchor in that file overrides the built-in ones.
No match means the file does not hold the new key. A match is good news, but keep going. Akamai warns that a correct file does not prove the running daemon loaded the key.
Check 2: did the running daemon load the new key?
For BIND, Akamai points to two commands:
sudo rndc managed-keys status
sudo rndc secroots -The first prints the current status of the managed-keys database. The second dumps the security roots, which are the trust anchors BIND is using. The - argument prints the dump to standard output. Without it, BIND writes the dump to its secroots file, which is named.secroots by default. Look for 38696 in the output of both commands. These descriptions come from the current BIND 9 manual, so check man rndc on your own version.
For Unbound, Akamai points to unbound-anchor. This tool sets up or updates the root trust anchor. It fetches root-anchors.xml from IANA over HTTPS and checks the result against a certificate. It reads and writes the anchor file with RFC 5011 tracking.
unbound-anchor -l
sudo unbound-anchor -v -a "$ANCHOR"The -l option lists the root key and certificate built into the tool itself. If 38696 is missing from that list, your unbound-anchor build is older than KSK-2024. The second command checks and updates the file. Do not rely on its exit code alone. The manual says it exits with 1 when it updated the anchor from the certificate, or when it used the built-in key. It exits with 0 when no update was necessary, when an RFC 5011 update was possible, or when an error occurred. A zero can hide an error, so run sudo grep 38696 "$ANCHOR" again afterwards. The manual says to run unbound-anchor before you start Unbound, so restart the daemon after any change:
sudo systemctl restart unboundThe sources here describe no such command for the other resolvers in this guide. For those, use the sentinel test below.
Check 3: run the RFC 8509 sentinel test against your own resolver
RFC 8509 defines special query labels. They ask a validating resolver whether it trusts a given key tag. Cloudflare published a ready-made pair under its test domain, dnstest.dev. Its example sends the queries to 1.1.1.1, which tests Cloudflare's resolver and not yours. Point them at your own:
dig @127.0.0.1 root-key-sentinel-is-ta-38696.dnstest.dev. A +noall +comments +answer
dig @127.0.0.1 root-key-sentinel-not-ta-38696.dnstest.dev. A +noall +comments +answeris-ta-38696 asks whether the key is trusted. not-ta-38696 asks whether it is not trusted. For a validating resolver that supports RFC 8509, read the two status: lines like this:
is-taanswers andnot-tareturns SERVFAIL. The resolver trusts KSK-2024. Cloudflare notes that the SERVFAIL onnot-tais expected here. The resolver deliberately rejects the "not trusted" query.is-tareturns SERVFAIL andnot-taanswers. The resolver does not trust KSK-2024.- Both answer. This proves nothing. Akamai calls it indeterminate, not a pass. RFC 8509 says a resolver without sentinel support gives no information about its trust anchors. A resolver that does not validate at all answers every query.
- Both return SERVFAIL. Cloudflare's table was written before the switch. Since 11 October, a resolver that never got KSK-2024 cannot validate
dnstest.devat all. Both queries then fail like every other name, which your triage already showed. Fix the anchor, then run the pair again.
Cloudflare adds one more rule. If sentinel support cannot be established, the result is inconclusive, and it does not mean the new key is missing.
Testing the Unbound behind Pi-hole or AdGuard Home
A Pi-hole or AdGuard Home in front of Unbound is a forwarder. RFC 8509 warns that a forwarder and its upstream can give indeterminate or mixed results when their trust state differs. So test Unbound directly, on the port it listens on:
dig @127.0.0.1 -p 5335 root-key-sentinel-is-ta-38696.dnstest.dev. A +noall +comments +answerPort 5335 is only an example. Use the port: value from your unbound.conf. Then test the Pi-hole or AdGuard address as well, because that is the address your clients actually ask. Two more caveats from RFC 8509 apply. A client with several resolvers configured can retry another one after a SERVFAIL. RFC 8509 says "the single-resolver test technique will not function reliably in such cases." Also, a SERVFAIL may be cached for up to 5 minutes, so wait that long before you repeat a test after a fix. Akamai also says to run the test from each network that depends on the resolver. That includes the phones and laptops you point at it for private DNS on your own devices.
How to fix DNSSEC after the root KSK rollover
Work through these steps in order. Run the three checks again after each one.
Step 1: update the resolver package
Akamai's advice is short: "Updating to a current software release resolves this in most cases, since recent builds ship with KSK-2024 included."
sudo apt update
apt policy unbound
sudo apt install --only-upgrade unbound
sudo systemctl restart unboundFor BIND the package is bind9. Knot Resolver ships as knot-resolver and PowerDNS Recursor as pdns-recursor. Swap the name in, then restart that service. apt may refuse to upgrade because of held or broken dependencies. In that case, fix the broken packages first.
This step matters most for PowerDNS Recursor. Its documentation says it has no support for RFC 5011 key rollover. It also does not save a changed root trust anchor to disk. The built-in key comes from the program itself, so a newer package is the normal way to get KSK-2024. systemd-resolved also has the root anchor built in, so upgrade the systemd package from your distribution. Confirm the result with the sentinel test against 127.0.0.53, not with a version number. Remember that an inconclusive result does not mean a failure.
You may rely on unattended-upgrades for automatic package updates. If so, read its log and confirm that the resolver package was really upgraded. Do not assume it was.
Step 2: take the anchor from IANA, never from a copy
If you cannot upgrade yet, load the anchor by hand. Akamai says to "retrieve the trust anchor from IANA directly rather than copying it from secondary sources." Do not paste a key from a forum post or a blog, including this one.
For Unbound, unbound-anchor already does this. It fetches root-anchors.xml from IANA and verifies it before it writes the file. The broken Unbound may be the only resolver on the box. Then the tool may not be able to look up IANA's server name. Its -f option makes it use a different resolv.conf file:
printf 'nameserver 9.9.9.9\n' > /tmp/resolv.anchor
sudo unbound-anchor -v -f /tmp/resolv.anchor -a "$ANCHOR"
sudo systemctl restart unboundThe tool ran as root, so check who owns the file now. Step 3 shows how.
For other resolvers, download the files from IANA's page at https://www.iana.org/dnssec/files. It lists root-anchors.xml and its signature, root-anchors.p7s. It also lists icannbundle.pem, the certificate bundle that you verify the signature with. Load the key in the format your resolver's documentation asks for. For PowerDNS Recursor that means dnssec.trustanchorfile. The recursor re-reads that file every 24 hours by default, so restart it to apply the change at once.
Step 3: make the anchor storage writable
RFC 5011 adds a new key only when the DNSKEY set that carries it "is validated by an existing trust anchor". KSK-2017 no longer signs the root zone. So a resolver that holds only key tag 20326 cannot learn 38696 through RFC 5011 any more. That is why steps 1 and 2 come first.
Write access still matters. ICANN's advice for a missing 38696 is to "verify that automatic trust updates are enabled and that your resolver has write permissions to its storage directory." Akamai describes the failure: "A resolver may recognize the new key but fail to save it if its trust anchor file or directory is read only." A resolver in that state works until it restarts and reads the old file again. The scheduled revocation of KSK-2017 in January 2027 is another RFC 5011 event, so the file must be writable then too.
For Unbound, check that the user it runs as can write the file. The username: setting in unbound.conf names that user:
grep -R "username:" /etc/unbound/
ls -ld "$(dirname "$ANCHOR")" "$ANCHOR"
sudo -u unbound test -w "$ANCHOR" && echo writableReplace unbound in the last line if your username: is different. No writable line means the daemon cannot save updates. Fix the owner of the file and of its directory. For Knot Resolver, the docs say anchors are saved to the file only "if allowed". The read-only flag blocks those updates, so remove it unless you manage the file yourself.
Step 4: rebuild your images, not only your servers
Fixing the running server does not fix the images you build servers from. Akamai warns: "Rebuilding a resolver from an older VM image, container, or appliance backup can restore the trust anchor that existed when the image was created." Update the golden images too. Otherwise "the outdated anchor returns the next time a system is rebuilt."
A resolver that runs in Docker Compose keeps its old image when you only restart it. Pull or rebuild the image so the new package or anchor is inside it:
docker compose pull
docker compose build --pull
docker compose up -dThe difference matters, and when a Compose restart is enough and when you must rebuild explains it. The same applies to VPS snapshots, and to the backups you keep for moving a server to a new VPS. A snapshot taken before the fix brings the old anchor back when you restore it.
Turning validation off is a stopgap
Akamai's guidance does not offer disabling validation as a workaround. It also says forwarding to an upstream provider does not help: "Forwarding queries to an upstream provider does not exempt a resolver that performs DNSSEC validation itself."
You may need name resolution back in the next few minutes. In that case you can turn validation off for a short time, but know the cost. While it is off, your resolver accepts forged answers for signed domains. Stopping that attack is the reason DNSSEC exists. For systemd-resolved, the Arch thread used DNSSEC=no. A drop-in file keeps the change easy to find and to remove:
sudo mkdir -p /etc/systemd/resolved.conf.d
printf '[Resolve]\nDNSSEC=no\n' | sudo tee /etc/systemd/resolved.conf.d/90-dnssec-stopgap.conf
sudo systemctl restart systemd-resolvedOther resolvers have their own switch in their own config. Whatever you change, write down when you changed it. Then fix the anchor with steps 1 to 3. Delete the drop-in, restart the service, and run the sentinel test again. For background on the system itself, see the history of DNS.
FAQ
Why does every domain return SERVFAIL since 11 October 2026?
On 11 October 2026 the root zone switched to KSK-2024, key tag 38696. A validating resolver that never loaded that key cannot validate the root, so it cannot validate anything under it. Akamai says signed and unsigned domains both fail. To confirm it, query a name with and without dig +cd. An answer with +cd and SERVFAIL without it means validation is failing. Then update the resolver package, or load the anchor from IANA.
Both sentinel queries answered. Is my resolver fine?
No, that result proves nothing. Akamai calls it indeterminate, not a pass. A resolver without RFC 8509 sentinel support gives no information about its trust anchors. A resolver that does not validate answers both queries. The passing pattern is an answer for root-key-sentinel-is-ta-38696 and SERVFAIL for root-key-sentinel-not-ta-38696.
Can automatic RFC 5011 updates still fix a resolver that missed KSK-2024?
Not on their own. RFC 5011 only accepts a new key from a DNSKEY set that an already trusted key validates, and KSK-2017 no longer signs the root zone. Update the resolver package or fetch the anchor from IANA. Then make the anchor file and its directory writable. The scheduled revocation of KSK-2017 in January 2027 also arrives through RFC 5011.
Should I delete KSK-2017, key tag 20326, from my anchor file?
You do not need to remove it by hand now. As of October 2026, IANA still lists KSK-2017 as a valid trust anchor, though it no longer signs the zone. Its revocation is scheduled for 11 January 2027, and its removal from the root zone for 22 March 2027. What matters today is that key tag 38696 is present and that the running daemon uses it.
Does a systemd-resolved no-signature error mean the rollover broke my server?
Not necessarily. Lines such as DNSSEC validation failed for question ... : no-signature and incompatible-server were reported in 2022 and 2025. That was long before the rollover, on systems where DNSSEC had been turned on. Run systemd-analyze cat-config systemd/resolved.conf and look for a DNSSEC= setting. Also check whether the errors began right after a systemd upgrade that changed the default.