RecursClients is a global NSStats counter that reports the total number of recursive clients awaiting resolution across all views. It does not break down which view is consuming the pool. When RecursClients climbs to 847 out of 1000, you know the pool is stressed but not whether the pressure is evenly distributed or whether one view is responsible for most of it.
NumFetch per view fills that gap. It is a view-scoped gauge of active outbound fetches to upstream nameservers, maintained independently for each view in the resolver statistics. Unlike cumulative counters that increment over time, NumFetch is an instantaneous gauge: it goes up when a fetch starts and down when the fetch completes, times out, or is aborted. A sustained upward trend in one view’s NumFetch while other views remain flat localizes a view-specific resolution problem that the global counter masks.
Each active fetch holds resources (a recursive-client slot, a file descriptor, memory for resolver state) until it completes or times out. When upstream nameservers respond quickly, fetches complete rapidly and NumFetch stays low. When upstream is slow or unreachable, fetches pile up and NumFetch climbs.
There is no per-view recursive-clients limit. The option is global, set only in the options block, and caps the sum across all views. One view’s runaway recursive load can exhaust the shared pool and starve other views.
How it works
Every DNS query arrives at BIND through view selection first. The match-clients and match-destinations directives in each view block determine which view processes the query. Once a view accepts a query and determines it needs recursion (cache miss, recursion enabled), the view’s resolver initiates one or more outbound fetches. NumFetch counts these active fetches per view.
All per-view fetches draw from the same recursive-clients pool. BIND maintains a single global table of recursive client slots, bounded by recursive-clients (default 1000). When the table reaches the soft quota (90%, or 900 by default), BIND logs rate-limited warnings and begins reclaiming the oldest slots. At the hard limit (1000), new recursive queries receive SERVFAIL.
This shared-pool architecture means one view’s slow upstream dependency can cascade into a global failure:
flowchart TD
CI["internal clients"] --> VI["View: internal
NumFetch: 45"]
CE["external clients"] --> VE["View: external
NumFetch: 780"]
CG["guest clients"] --> VG["View: guest
NumFetch: 22"]
VI -->|"recursion"| RC["Shared recursive-clients
847 of 1000 slots"]
VE -->|"recursion"| RC
VG -->|"recursion"| RC
RC --> SQ["soft quota: 900"]
RC --> HL["hard limit: 1000
SERVFAIL for all"]If the external view’s forwarder becomes unreachable, every query the external view sends upstream occupies a slot for the resolver-query-timeout duration (default 10 seconds). As those slots accumulate, fewer remain for the internal and guest views. Eventually all views suffer SERVFAIL even though only one view has an upstream problem. If external-view NumFetch is climbing while internal-view NumFetch stays flat, you have localized the problem before RecursClients reaches the soft quota.
Collecting NumFetch per view
The statistics channel exposes NumFetch under each view’s resolver stats. The port depends on your statistics-channels configuration (commonly 8053 or 8653):
# Dump NumFetch for every view from the JSON statistics channel
curl -s http://localhost:8653/json/v1/server | \
python3 -c "import sys,json; d=json.load(sys.stdin); \
[print(f'{v}: NumFetch={vd.get(\"resolver\",{}).get(\"stats\",{}).get(\"NumFetch\",\"N/A\")}') \
for v,vd in d.get('views',{}).items()]"
If the statistics channel is not enabled, rndc stats writes per-view resolver statistics (including NumFetch) to the configured statistics file. The path varies by distribution; check your statistics-file setting:
rndc stats
grep NumFetch /var/named/data/named_stats.txt
During an active incident, rndc recursing shows every in-flight recursive query along with the upstream nameserver it is waiting on. This is the next level of detail after NumFetch identifies which view is under pressure:
# Summarize which upstream nameservers queries are waiting on
rndc recursing | awk '{print $NF}' | sort | uniq -c | sort -rn | head -10
Version notes
Counter names are stable across BIND 9.16 and later. Zero-valued counters are omitted from non-verbose statistics channel output, so a view with NumFetch at 0 may not appear unless verbose mode is enabled.
On BIND 9.18.x, the global RecursClients counter had known bugs where the value could underflow (drop below zero) or overflow in certain resolution scenarios. These were fixed in subsequent patch releases. The per-view NumFetch counter was not mentioned as affected. If you are running an older 9.18.x patch level and see impossible RecursClients values, rely on per-view NumFetch for a more trustworthy picture.
When it matters
NumFetch per view matters in any deployment where multiple views share a single named process and a single recursive-clients pool:
- Split-horizon resolvers with separate internal and external views. The internal view may forward to corporate DNS while the external view resolves against public nameservers. A failure in either forwarding path shows up as elevated NumFetch in only that view.
- Multi-tenant DNS where different client classes receive different views. One tenant’s misconfigured application generating excessive unique queries drives up that view’s NumFetch without affecting others.
- Guest or DMZ networks resolving through a different upstream path than production networks. A guest-network upstream degradation is isolated in the guest view’s NumFetch.
- Mixed-role instances serving both authoritative zones and recursive resolution through different views. Recursive pressure in the resolving view is distinguishable from authoritative query load.
Use NumFetch per view when:
- RecursClients is trending toward 50% of the limit and you need early warning about which view is the heaviest consumer.
- One view’s clients report intermittent DNS failures while others are unaffected.
- A forwarder change affects one view’s upstream path and you need to confirm the impact.
- You are planning capacity and need to know which view drives recursive load growth.
The global counter suffices when you run a single-view resolver, or when all views share the same upstream path and a homogeneous client population. If you are monitoring specifically for the recursive-clients circuit breaker, RecursClients as a percentage of the limit is the right signal for that.
Important limitation: there is no per-view recursive-clients cap. You cannot configure BIND to limit one view to 300 recursive clients and another to 700. The global limit applies to the sum. If one view’s traffic is consuming a disproportionate share, the response is operational (investigate and mitigate the upstream cause in that view) rather than configurational (set a per-view quota).
Signals to watch
NumFetch per view is most useful when correlated with other per-view resolver signals.
| Signal | Why it matters | Warning sign |
|---|---|---|
| NumFetch per view | Localizes recursive pressure to a specific view | One view trending up while others stay flat |
| RecursClients (global) | Shows total recursive pool utilization against the limit | Approaching 900 (soft quota) or 1000 (hard limit) |
| Per-view cache hit ratio | Falling hit ratio drives more fetches in that view | Decline in the same view where NumFetch is rising |
| Per-view RTT distribution | Slow upstream increases fetch duration, holding slots longer | Shift toward higher RTT buckets (QryRTT1600+) in one view |
| Per-view QueryTimeout | Timeouts hold slots for the full resolver-query-timeout | Rate exceeding 5% of outbound queries in one view |
| Per-view CacheMisses | High miss rate means more outbound fetches | Spike concentrated in one view, possibly from random subdomain queries |
The diagnostic chain: NumFetch identifies the view under pressure. Cache hit ratio in that view tells you whether the pressure is from cache misses (more queries need recursion) or slow upstream (the same fetches take longer). RTT distribution confirms upstream latency. QueryTimeout tells you whether upstream is not responding at all.
How Netdata helps
- Collects NumFetch per view at per-second resolution from the BIND statistics channel, without manual polling or delta computation.
- Correlates per-view NumFetch with the global RecursClients gauge in the same dashboard, showing what fraction of the shared pool each view is consuming at any moment.
- Surfaces per-view cache hit ratio, RTT distribution, and QueryTimeout alongside NumFetch, making the cause-effect chain visible without switching tools.
- Applies ML anomaly detection to per-view NumFetch trends, flagging a sustained upward drift in one view before the global RecursClients crosses a threshold.
Related guides
- How BIND actually works in production: a mental model for operators
- BIND monitoring checklist: the signals every production resolver and authoritative server needs
- BIND monitoring maturity model: from survival to expert
- BIND ’no more recursive clients: quota reached’: the recursive-clients circuit breaker
- named not responding on port 53: total outage versus UDP-works-TCP-fails
- BIND NXDOMAIN spike: DGA malware, water torture, and Windows suffix search lists
- BIND REFUSED responses: ACL denials, recursion policy, and clients that get locked out
- rndc not responding: control-plane failure while queries still work
- BIND SERVFAIL responses: what a DNS SERVFAIL actually means and how to trace the cause






