BIND (named) processes queries through a pipeline: receive packet, parse, ACL/view check, cache lookup (if recursive), zone lookup (if authoritative), recursive fetch on cache miss, apply RPZ/DNSSEC, serialize response, send. Every signal below maps to a stage in that pipeline or a resource it competes for: CPU, memory, file descriptors, network buffers, source ports.

The levels are cumulative. Most signals come from the statistics channel (JSON at /json/v1/server, explicitly configured in named.conf). The rndc stats file is an alternative but appends indefinitely and can fill disk if not rotated. Commands below assume a single named process (standard deployment; BIND is multithreaded, not multiprocess).

The maturity framework

flowchart TD
    L1["Level 1: Survival - is it alive?"]
    L2["Level 2: Operational - degradation detection"]
    L3["Level 3: Mature - leading indicators"]
    L4["Level 4: Expert - per-thread, per-upstream"]

    L1 --> L2 --> L3 --> L4
  • Level 1: Survival - Is named alive and answering? Catches total outages only.
  • Level 2: Operational - Common degradation before it becomes an outage. Minimum for production.
  • Level 3: Mature - Leading indicators and internal state. Problems visible hours to days before user impact.
  • Level 4: Expert - Per-thread, per-view, per-upstream granularity. Added after major incidents.

Level 1: Survival

SignalWhy it mattersHow to check
Process livenessIf named is gone, DNS fails for all clientspgrep -x named (use -x, not -f, to avoid false matches on named-checkzone)
Functional UDP query (role-correct)UDP carries 95%+ of DNS trafficRecursive: dig +time=2 +tries=1 @127.0.0.1 example.com A. Authoritative: dig +time=2 +tries=1 +norecurse @127.0.0.1 <your-zone> SOA
Functional TCP queryTCP carries zone transfers, large responses, DNSSECSame probe with +tcp
Process memory (RSS)Unbounded growth leads to OOM killawk '/VmRSS/{print $2}' /proc/$(pgrep -x named)/status (value in kB)

A REFUSED response means ACL denial, not service failure. An authoritative server returns REFUSED for queries outside its zones. The canaries above already account for this.

Level 2: Operational

SignalWhy it mattersHow to check
Incoming query rateBaseline traffic. Sudden drop = listener failure or network partition. Spike = DDoS or flash crowdRequestv4, Requestv6 in NSStats via statistics channel
SERVFAIL rateServer is up but failing to resolve. Most important error signalQrySERVFAIL / (QrySuccess + QrySERVFAIL + QryNXDOMAIN + QryFORMERR + QryNxrrset + QryReferral). Normal: near 0%. Alert: >0.1%. Critical: >1%
Recursive clients in-flightBIND’s circuit breaker. Soft quota at 90% of limit (default 900). Hard limit at 100% (default 1000) = all new recursive queries get SERVFAILRecursClients in NSStats as % of recursive-clients config. Normal: <30%. Alert: >50%. Critical: >90%
Cache hit ratioLow hit ratio = high latency, more upstream load, beginning of recursive painCacheHits / (CacheHits + CacheMisses) per view. Should be >90% after warmup (30-60 min post-restart)
Protocol distributionTCP share normally <5%. Elevation indicates truncation, transfers, or attacksQryUDP vs QryTCP in NSStats
Query rejection rateACL denials from legitimate clients indicate misconfigurationAuthQryRej, RecQryRej in NSStats
CPU utilizationDNSSEC validation, query parsing, RPZ matching all consume CPUpidstat -p $(pgrep -x named) or /proc/$(pgrep -x named)/stat
File descriptor usageFD exhaustion causes silent query drops. Default ulimit -n (often 1024) is dangerously lowls /proc/$(pgrep -x named)/fd | wc -l vs grep "Max open files" /proc/$(pgrep -x named)/limits. Peak should not exceed 50% of limit
Zone transfer / SOA serialSecondaries serving stale data is a ticking bomb. Serial mismatch persisting beyond refresh interval indicates transfer failuredig @primary <zone> SOA +short vs dig @secondary <zone> SOA +short (compare serial, third field)
DNSSEC validation failuresValFail produces SERVFAIL for signed domains. Broad failures across unrelated domains usually mean local problemValFail in per-view resolver stats. Should be 0 or near-0
Zone load health after reloadnamed starts successfully even if zones fail to load. rndc status reports “running” but the zone does not workrndc status | grep -i zones for zone count, then journalctl -u named --since "5 min ago" | grep -i "zone.*loaded|zone.*failed" (service name is bind9 on Debian/Ubuntu)

SERVFAIL is cached (negative caching). A momentary upstream outage causes sustained SERVFAIL for the negative TTL duration. Fixing upstream does not instantly fix the metric. On public recursive resolvers, some broken external domains produce background SERVFAIL. Breadth and trend matter more than individual occurrences.

Level 3: Mature

SignalWhy it mattersHow to check
Resolver RTT distributionUpstream latency directly drives cache-miss latency for users. Shift toward higher buckets indicates upstream degradationQryRTT10, QryRTT100, QryRTT500, QryRTT800, QryRTT1600, QryRTT1600+ per view
Resolver failure countersQueryTimeout holds a recursive-client slot for up to resolver-query-timeout seconds (default 10s) per timed-out queryQueryTimeout, Lame, QuerySockFail, QueryAbort, Retry per view. Normal: <2% timeouts. Alert: >5%. Critical: >20%
Active resolver queries per viewPer-view version of recursive workload pressureNumFetch per view (gauge, not counter)
Response code breakdownNXDOMAIN spike may indicate DGA malware or water torture attackNOERROR, NXDOMAIN, SERVFAIL, REFUSED individually from rcodes section
UDP RcvbufErrorsPackets dropped by kernel before BIND sees them. Invisible to BIND statistics. The single most systematic monitoring gapcat /proc/net/snmp | grep Udp (UdpRcvbufErrors column). Any sustained non-zero rate is abnormal
TCP connection countTCP accumulation can exhaust FDs. Hidden by UDP-only health checksss -tan '( sport = :53 )'
RRL activityRate limiting affecting legitimate traffic. RateSlipped causes TCP retryRateDropped, RateSlipped in NSStats
RPZ rewritesSpike indicates malware outbreak or botnet activityRPZRewrites in NSStats
Update activityUpdateFail spikes indicate unauthorized update attempts or broken automationUpdateDone, UpdateFail in NSStats
Socket statisticsSocket activity patterns for FD exhaustion diagnosisSockStats counters
OpCode and QType distributionANY query spikes indicate amplification attacks. TXT spikes may indicate DNS tunnelingopcodes and qtypes maps
SOA expire countdownReal danger signal for secondaries. At expiry, secondary stops serving the zone entirelyrndc zonestatus <zone> shows expire time. Alert when below 50%. Critical when below 25% or 24 hours
Cache eviction countersDeleteLRU increasing rapidly indicates cache at capacity and evicting entriesDeleteLRU, DeleteTTL in per-view cachestats
Control-plane responsivenessIf rndc hangs while queries work, incident response is impairedtimeout 5 rndc status >/dev/null 2>&1 && echo OK || echo FAIL

Level 4: Expert

SignalWhy it mattersHow to check
Per-thread CPU utilizationSingle saturated thread bottlenecks whole server while aggregate CPU looks moderatepidstat -t -p $(pgrep -x named)
rndc recursing samplingShows which upstream nameservers are causing pile-up during recursive resolution cascaderndc recursing | awk '{print $NF}' | sort | uniq -c | sort -rn | head
Cache memory trackingTreeMemInUse and HeapMemInUse trending up indicates memory pressure before OOMTreeMemInUse, HeapMemInUse, CacheNodes in cachestats
RRSIG expiry monitoringSilent signing failure leads to worldwide SERVFAIL when signatures expire. Authoritative server does not validate its own signaturesdig @127.0.0.1 <zone> RRSIG +dnssec +multiline for validity window. Alert when below 25% of signature lifetime
Query name entropyHigh entropy (random subdomains) indicates water torture attack. Near-zero repetition per unique query nameQuery log sampling or rndc dumpdb -cache analysis (warning: expensive on large caches, causes I/O pressure)
NTP clock offsetClock drift causes DNSSEC validation failurestimedatectl status or chronyc tracking
Per-core CPU and IRQ/softirqSingle-core bottleneck under high packets-per-second load. Bandwidth may have headroom (pps limit, not bps)mpstat -P ALL 1 5
Source port entropyPoor randomization = cache poisoning vulnerabilitydig +short porttest.dns-oarc.net TXT @127.0.0.1
Statistics channel response timeSlow polling = BIND under severe internal pressureTime the curl request to statistics channel
Zone file integrity checksumsDetect unauthorized zone modificationsChecksum comparison after each reload
Post-reload zone load verificationCatches zones that failed to load after rndc reload. named continues running but the zone does not workrndc zonestatus <zone> for each zone, or log scan for load failures
DNSSEC signing freshnessMissing .signed.jnl = zone not signed (silent failure, no log error). Key file missing produces no log errorls -la /var/named/data/<zone>.signed.jnl 2>/dev/null || echo "NOT SIGNED" (path varies by distribution)

Role-specific priorities

Recursive resolvers: prioritize cache hit ratio, recursive clients as percentage of limit, upstream RTT distribution, DNSSEC validation failures, and UDP RcvbufErrors. The cache is the dominant memory consumer and the primary value the resolver provides.

Authoritative-only servers: prioritize zone load health, transfer state, SOA serial and expire countdown, DNSSEC signing freshness for inline-signed zones, and TCP behavior. Zone data can dwarf cache memory on servers with many zones.

Mixed-role deployments (recursive and authoritative on the same instance) are the hardest to reason about. Recursive and authoritative failure signals mask each other in aggregate statistics. Per-view monitoring is essential. A zone-specific authoritative failure can hide behind recursive traffic noise.

Common blind spots

Kernel-level UDP drops. BIND statistics only count queries it read from the socket. Queries dropped by the kernel (receive buffer overflow) are invisible to BIND: no log, no counter. The only evidence is UdpRcvbufErrors in /proc/net/snmp. Most teams discover this during an incident where BIND is healthy but queries are disappearing.

Recursive-clients as a cliff edge. This is BIND’s circuit breaker. When it trips, every recursive query gets SERVFAIL. The soft quota at 90% (default 900) starts rejecting before the hard limit (1000). Monitor RecursClients as a percentage of the configured limit, not an absolute number.

SOA expire runway. Zone transfer failures are silent and time-delayed. Secondaries serve stale data until the SOA expire timer runs out, then SERVFAIL. The danger is not serial mismatch alone but the expire countdown to zero.

DNSSEC signature expiry for authored zones. Auto-signing can silently fail (key file permissions, disk full). Missing key files produce no log error and no .signed.jnl file. The authoritative server does not validate its own signatures. Validating resolvers worldwide reject the zone when signatures expire.

How Netdata helps

  • Collects RecursClients as an absolute gauge, not a cumulative counter, so you see real-time recursive client utilization without computing deltas.
  • Correlates the recursive resolution cascade in one view: RecursClients climbing toward limit, QueryTimeout increasing, QrySERVFAIL rising, cache hit ratio declining. These four signals together confirm upstream slowness cascading into local failure.
  • Surfaces OS-level signals (UdpRcvbufErrors from /proc/net/snmp, FD usage from /proc/<pid>/fd, per-core CPU) alongside BIND statistics channel data, closing the gap between kernel-level packet drops and BIND-level query counters.
  • Provides per-view cache hit ratio and eviction counters (DeleteLRU, DeleteTTL) for split-horizon deployments where aggregate statistics mask view-specific problems.
  • Excludes the internal BucketSize stat from RTT histograms automatically.
  • Handles statistics channel polling at safe intervals with rate computation, avoiding the overhead that polling too frequently (under 5 seconds) adds on busy resolvers.