I Know This Error Hurts
You're staring at an error in your DNS management console or BIND logs saying the zone transfer failed. It's frustrating because DNS is supposed to just work. But here's the truth: 9 times out of 10, it's a simple permission problem. Let me show you the fix I've used on Windows Server 2016 through 2022, and on BIND 9.x.
The Fix: Check Your ACLs
The first thing to verify is the Access Control List (ACL) on your zone. If the secondary DNS server doesn't have permission to read the zone, the transfer fails silently.
On Windows Server
- Open DNS Manager (dnsmgmt.msc).
- Right-click your zone, go to Properties.
- Click the Zone Transfers tab.
- Check Allow zone transfers is set to Only to the following servers.
- Add the IP of your secondary DNS server. Don't use names—use static IPs.
- Click Notify and make sure Automatically notify is on.
# If you prefer PowerShell:
Set-DnsServerPrimaryZone -Name "example.com" -Notify Notify -SecondaryServers "192.168.1.10", "192.168.1.11"
Add-DnsServerZoneTransferPolicy -Name "AllowSecondary" -ZoneName "example.com" -Action Grant -Servers "192.168.1.10", "192.168.1.11"
On BIND (Linux)
- Open your zone file, usually in
/etc/bind/. - Add an
allow-transferline to the zone definition innamed.conf. - Restart BIND:
systemctl restart bind9
zone "example.com" IN {
type master;
file "/etc/bind/db.example.com";
allow-transfer { 192.168.1.10; 192.168.1.11; };
};
Why This Works
DNS zone transfers use TCP port 53. If the secondary server can talk to the primary, the error is almost always a missing permission in the ACL. By explicitly listing which servers can request a transfer, you stop random hosts from pulling your zone data—and you fix the error. The primary server just says "no" silently if the IP isn't in the list.
Less Common Variations That Trip People Up
1. Firewall Blocks TCP 53
Most firewalls allow UDP 53 for queries, but zone transfers need TCP. Check your Windows Firewall or iptables. On Windows, make sure the DNS (TCP) rule is enabled. On Linux:
iptables -A INPUT -p tcp --dport 53 -s 192.168.1.10 -j ACCEPT
2. TSIG Key Mismatch
If you're using Transaction Signatures (TSIG) for secure transfers, both servers must have the same key. On Windows, check the Trust Points in DNS Manager. On BIND, compare /etc/bind/keys.conf on both sides. One wrong character and the transfer fails.
3. Zone Serial Number Not Updated
If you make a change to the zone but forget to increment the serial number, the secondary thinks nothing changed. This isn't a true failure—the transfer just doesn't happen. Always bump the serial when you add or remove records.
4. Secondary Server Has Wrong Zone Type
Double-check the secondary server is set to Secondary Zone, not Stub Zone or Forward Lookup Zone. Stub zones only get nameserver records, not the full zone. This one got me good back in 2018.
How to Prevent This From Happening Again
- Document your ACLs. Every time you add a secondary DNS server, add its IP to the primary's allow-transfer list right away. Don't rely on memory.
- Monitor DNS logs. On Windows, enable DNS debug logging for a few minutes to see the exact error. On BIND, check
/var/log/syslogfor messages likezone example.com/IN: refused transfer from client 192.168.1.10. - Test after every change. Use
nslookupordigto verify the secondary has the zone. A quickdig @secondary-server example.com axfrshows if it worked. - Keep both servers in sync. If you upgrade the primary, upgrade the secondary too. Incompatible versions can break transfers.
"The fix is almost always in the ACL. I've seen admins spend hours on firewall rules when the zone itself just said 'no' to the secondary IP." — Me, after fixing this for a client in 2021
If you've checked all this and it still fails, open a capture with Wireshark or tcpdump. Filter for TCP port 53 and look for RST packets. That'll tell you if the firewall is the real culprit. But honestly, 90% of the time, it's the ACL. Fix that, and you're golden.