REFUSED (DNS rcode 5) is a deliberate policy decision: BIND received the query, parsed it, and chose not to answer. The server is alive, listening, and processing queries. It is configured to reject this particular query from this particular source.

The actionable scenario: legitimate client subnets that previously resolved names or queried your zones suddenly start receiving REFUSED, typically after a configuration change. The fix is almost always an ACL or view mismatch, not a restart.

Background REFUSED from random Internet hosts hitting a public authoritative server is normal noise. Open-recursion probes, amplification reconnaissance, and scanner traffic generate REFUSED continuously. A public authoritative server with recursion no; correctly returns REFUSED for queries outside its zones. These are not incidents.

What it means

BIND evaluates ACLs early in the query pipeline, before cache lookup or zone lookup. When a query fails an ACL check, BIND returns an empty response with RCODE set to REFUSED. No records, no additional section, no recursion attempted.

Three ACL directives control who gets REFUSED:

  • allow-query controls which sources can send any query at all. If a client fails this check, it gets REFUSED for everything, including zones the server is authoritative for. Default: { any; }. This is the broadest gate.

  • allow-recursion controls which sources can trigger recursive resolution. Default: { localnets; localhost; }. Clients outside this ACL who send recursive queries get REFUSED instead of resolution.

  • allow-query-cache controls which sources can receive answers from the cache. If not explicitly set, it inherits from allow-recursion. Default when recursion no; is set: { none; }.

Key inheritance rule: allow-query-cache inherits from allow-recursion when not explicitly set. The reverse is not true. If you set allow-recursion { 10.0.0.0/8; }; without setting allow-query-cache, cache access inherits { 10.0.0.0/8; } and both match. But if you set allow-query-cache without allow-recursion, recursion stays at the default { localnets; localhost; } while cache access is restricted. This asymmetry produces unexpected REFUSED from clients that can reach the cache but not recurse, or vice versa.

Views add another layer. If your configuration uses views and a client matches a view that does not contain the requested zone, the response is REFUSED, even if the zone exists in another view. Every zone that needs to be visible to a client must exist in the view that client matches.

REFUSED is also the response when a zone fails to load. If named starts or reloads successfully but a zone file has a syntax error or is missing, that specific zone is not served. Queries to it return REFUSED or SERVFAIL, while all other zones continue working. rndc status shows “running” with no indication of the failure.

Common causes

CauseWhat it looks likeFirst thing to check
allow-query too restrictiveClient gets REFUSED for all queries, including authoritative zones they should seenamed-checkconf -p | grep allow-query
allow-recursion / allow-query-cache mismatchClient gets REFUSED only for recursive queries; authoritative queries workCompare both ACLs in the config
Client outside localnets after network changeSubnet that moved or was re-IP’d suddenly gets REFUSED on recursionCheck localnets value and client source IP
View without the requested zoneClient gets REFUSED for a zone that exists in another viewList zones in the matching view
Zone failed to loadREFUSED or SERVFAIL for one zone only, after reloadrndc zonestatus <zone> and logs
recursion no; on a server clients expect to recurseAll recursive queries get REFUSED; authoritative still worksCheck whether the server role changed

Quick checks

# Reproduce the REFUSED from the affected client's perspective
dig +time=2 +tries=1 @<server-ip> example.com A
# Look for: status: REFUSED

# Check the effective ACL configuration (includes defaults)
named-checkconf -p /etc/named.conf | grep -i "allow-query\|allow-recursion\|allow-query-cache\|recursion"

# Check REFUSED counts in the statistics channel
# NOTE: The statistics channel has no default port. It must be explicitly
# configured with 'statistics-channels'. Adjust the port to match your config.
<!-- TODO: verify JSON field names/structure across BIND versions. The JSON
format changed between 9.10, 9.16, and 9.18. These snippets assume a dict-style
layout; some versions return arrays of {name,value} objects. -->
curl -s http://localhost:8653/json/v1/server | \
  python3 -c "import sys,json; d=json.load(sys.stdin); \
  [print(f'{k}: {v}') for k,v in sorted(d.get('rcodes',{}).items())]"

# Check query rejection counters in nsstats
curl -s http://localhost:8653/json/v1/server | \
  python3 -c "import sys,json; d=json.load(sys.stdin); \
  [print(f'{k}: {v}') for k,v in d.get('nsstats',{}).items() if 'Rej' in k]"

# Check zone load status for a specific zone
rndc zonestatus example.com

# Check for REFUSED or denied entries in BIND security logs
# Common paths: /var/log/named/security.log (Debian/Ubuntu)
#               /var/named/data/named.security.log (RHEL/CentOS)
grep -i "refused\|denied" /var/log/named/security.log | tail -20

How to diagnose it

flowchart TD
    A["Client gets REFUSED"] --> B{"Known client subnet?"}
    B -- "No" --> C["Normal background noise"]
    B -- "Yes" --> D{"Authoritative query also REFUSED?"}
    D -- "Yes" --> E["Check allow-query and views"]
    D -- "No: recursive only" --> F["Check allow-recursion / allow-query-cache"]
    E --> G["Verify zone loaded: rndc zonestatus"]
    F --> G
  1. Confirm the response code. Run dig from the affected client (or simulate its source IP) and verify the status line reads REFUSED. A timeout looks different. SERVFAIL looks different. NXDOMAIN looks different. REFUSED means BIND saw the query and rejected it by policy.

  2. Determine the query type. Is the client querying a zone the server is authoritative for, or requesting recursion? If authoritative queries also get REFUSED, allow-query or a view mismatch is the culprit. If only recursive queries fail, the problem is in allow-recursion or allow-query-cache.

  3. Check the effective ACLs. Run named-checkconf -p to print the parsed configuration, including defaults. Verify that the affected client’s source IP or subnet appears in the relevant ACL. Pay attention to localnets, which is derived from the server’s interface addresses and netmasks. A network re-IP or interface change silently shifts what localnets covers.

  4. Check for view mismatch. If your config uses views, identify which view the client matches based on match-clients and confirm the requested zone exists in that view. A zone present in the “external” view but not the “internal” view produces REFUSED for internal clients.

  5. Check zone load health. Run rndc zonestatus <zone> for the affected zone. If the zone is not loaded, check logs for load errors. A zone that failed to load after rndc reload produces REFUSED with no obvious ACL cause.

  6. Distinguish from SERVFAIL. REFUSED is a policy rejection. SERVFAIL means BIND tried to process the query but encountered a deeper failure: upstream timeout, DNSSEC validation failure, zone data corruption, recursive client exhaustion. If clients report “DNS is broken” and you see both REFUSED and SERVFAIL, investigate them separately. See BIND SERVFAIL responses for the SERVFAIL diagnostic path.

  7. Correlate with recent changes. REFUSED from legitimate clients almost always follows a configuration change. Check for recent rndc reload events, named.conf edits, or network changes that shifted localnets.

Metrics and signals to monitor

SignalWhy it mattersWarning sign
REFUSED count in rcodes sectionDirect measure of REFUSED responses servedSudden increase above baseline
AuthQryRej in nsstatsAuthoritative queries rejected by ACLIncrease from known client subnets
RecQryRej in nsstatsRecursive queries rejected by ACLIncrease from known client subnets
Per-view resolver REFUSEDOutbound queries refused by upstreamCan cascade into SERVFAIL for clients
Zone load statusZones that fail to load produce REFUSEDMissing zones after reload
Config change eventsREFUSED spikes correlate with config editsTemporal proximity to rndc reload

There is no QryREFUSED counter in nsstats. The REFUSED response code count lives in the top-level rcodes section of the statistics channel. The per-view resolver REFUSED counter tracks outbound recursive queries that received REFUSED from upstream nameservers, which is a different signal entirely. Confusing these two leads to misdiagnosis.

Fixes

allow-query too restrictive

If legitimate clients get REFUSED for all queries including authoritative zones, allow-query is excluding them. Either widen the ACL to include their subnet or verify that allow-query is not inadvertently set to something narrower than intended.

The default is { any; }. Most authoritative servers should leave this at default unless they have a specific reason to restrict query sources.

allow-recursion / allow-query-cache mismatch

If recursive queries fail but authoritative queries work, check both ACLs. Remember the inheritance: allow-query-cache inherits from allow-recursion, not the reverse.

Set both explicitly to the same ACL if you intend them to match. If you set only allow-query-cache, allow-recursion stays at the default { localnets; localhost; }, creating a mismatch where cache access is restricted but recursion is not.

Client outside localnets

If a client subnet that should have recursion access gets REFUSED, check whether the subnet is covered by localnets. The localnets ACL is automatically derived from the server’s network interface configuration. A server that was re-IP’d, moved to a different VLAN, or had interfaces added or removed will have a different localnets scope.

Fix: explicitly list the client subnet in allow-recursion and allow-query-cache rather than relying on localnets alone.

View without zone

If the client matches a view that does not contain the requested zone, add the zone to that view. Every zone that needs to be visible to clients matching a particular view must be declared within that view’s configuration block.

Zone failed to load

Check the BIND logs for zone load errors after the last reload. Validate the zone file with named-checkzone before reloading. If the zone file has a syntax error, fix it and reload that specific zone with rndc reload <zone>.

Always run named-checkconf and named-checkzone before production reloads.

Prevention

  • Validate before reload. Run named-checkconf /etc/named.conf and named-checkzone <zone> <zonefile> before every rndc reload. This catches syntax errors, path mismatches, and ACL typos before they affect production.
  • Verify after reload. After any reload, check rndc zonestatus for production zones and scan logs for load failures.
  • Explicit ACLs over implicit. Do not rely solely on localnets for recursion access. Explicitly list client subnets in allow-recursion and allow-query-cache so that network changes do not silently lock out clients.
  • Monitor REFUSED as a ratio. Track REFUSED as a percentage of total responses and alert on sustained increases from known client subnets. Background REFUSED from random Internet sources is expected and should not trigger alerts.
  • Use canary probes. Deploy synthetic queries from known-authorized source IPs that exercise both authoritative and recursive paths. A REFUSED from a canary probe is an unambiguous signal of an ACL or view regression.

How Netdata helps

  • Per-second RCODE distribution including REFUSED lets you pinpoint the exact moment a spike begins and correlate it with config change timestamps or deployment events.
  • Query rejection counters (AuthQryRej, RecQryRej) are collected from the statistics channel and trended, making it visible when rejections shift from background noise to a legitimate-client problem.
  • Per-view resolver statistics including outbound REFUSED are collected separately from inbound rcodes, helping distinguish “my clients are locked out” from “my upstream is refusing me.”
  • Zone load health correlation with REFUSED spikes after reload events helps identify the “zone didn’t load” failure pattern without manual log diving.
  • ML anomaly detection on REFUSED rates learns the normal background noise level for your authoritative servers and surfaces deviations that represent real ACL regressions.