A client agent’s consul.client.rpc.failed counter ticks up. The agent process is running, gossip reports the node as alive, local health checks execute on schedule, and consul members lists the node as healthy. The server cluster looks fine: leadership is stable, Raft commit times are normal, and there is no election noise. Nothing on the standard dashboard is red.
The catalog is going stale anyway.
Consul runs two independent network paths between an agent and the server cluster. Gossip membership flows over LAN Serf (TCP and UDP port 8301). State updates flow over the server RPC pipeline (TCP port 8300). The first can be perfectly healthy while the second is broken, and most dashboards only watch the first. Anti-entropy sync runs on a fixed interval and pushes local agent state to the server catalog over RPC. When RPC fails, the catalog stops receiving updates from that agent but keeps serving whatever it last knew. Consumers (DNS, HTTP API, load balancer integrations, service mesh sidecars) keep getting answers, just progressively wrong ones.
For the broader architecture, see the mental model. For the full signal list, see the monitoring checklist. This article is the narrow playbook for elevated consul.client.rpc.failed.
What this means
consul.client.rpc.failed is a counter that increments whenever a client agent attempts an RPC against a server and the call fails. The companion counter consul.client.rpc counts every attempt. A healthy agent shows consul.client.rpc.failed flat or near zero, with consul.client.rpc ticking at the anti-entropy cadence plus any watches or DNS forwarding.
When the failed counter climbs, the agent cannot push the following to the catalog:
- New service registrations and deregistrations
- Health check transitions (passing to critical, or the reverse)
- Coordinate updates used by network coordinates
- KV writes routed through the agent
The agent keeps running checks locally, so a process that crashed on the host is correctly marked critical in the agent’s local state, but that critical state never reaches the catalog. From the catalog’s perspective the instance still looks healthy. Load balancers and service mesh sidecars that read from the catalog keep sending traffic to a dead endpoint.
flowchart LR A[Client agent
checks run locally] -->|gossip 8301 OK| B[Server cluster
alive in members] A -->|RPC 8300 FAIL| C[Catalog
stale state] A -->|anti-entropy| C C -->|serves stale| D[DNS / API / LB
route to dead instance]
The asymmetry is the trap. Gossip works, so the node appears alive. The leader is stable, so server dashboards are green. The failure is silent and visible only in two places: the consul.client.rpc.failed counter on the affected agent, and drift between what the agent believes locally and what the catalog exposes.
Common causes
| Cause | What it looks like | First thing to check |
|---|---|---|
| Firewall blocks 8300 while 8301 stays open | One agent or one subnet suddenly failing RPC after a security-group change; consul members still lists the node as alive | nc -zv <server-ip> 8300 from the agent host |
| Server RPC handler exhausted (file descriptors) | Many agents across different subnets fail simultaneously; server logs show accept errors; server consul.runtime.sys_fd_used near limit | FD usage on servers vs ulimit -n |
TLS certificate mismatch with verify_server_hostname | Failures appear after a cert rotation; agent logs show x509: certificate is valid for X, not server.<dc>.consul.<domain> | Agent logs for TLS error strings |
| ACL token lacks permission for the RPC method | Failures scoped to one method (often Coordinate.Update); agent logs show Permission denied | Agent logs for ACL denied strings |
| Agent has no known servers | known_servers: 0 in consul info; logs show No known Consul servers; common after servers are replaced with new IPs | consul info on the affected agent |
A subtle variant: if the agent’s own rate limiter (the limits block) is configured too aggressively, the counter that climbs is consul.client.rpc.exceeded, not consul.client.rpc.failed. The RPC is rejected locally before it leaves the agent, so there is no connection error in the logs. Treat sustained non-zero consul.client.rpc.exceeded as the same class of problem: the agent is not getting state to servers.
Quick checks
Run these on the affected client agent first, then on a server. All are read-only and safe during incidents.
# How many servers does this agent know about?
consul info | grep -A2 "known_servers"
# Is the agent alive in gossip from the server side?
consul members
# Is the RPC port actually reachable from this agent?
nc -zv <server-ip> 8300
# Pull the RPC counters from the agent's telemetry
curl -s http://127.0.0.1:8500/v1/agent/metrics | grep -E "consul.client.rpc"
# Agent self view: known servers and config
curl -s http://127.0.0.1:8500/v1/agent/self | jq '.Stats.consul | {known_servers, server}'
# Check anti-entropy sync outcome from agent telemetry
curl -s http://127.0.0.1:8500/v1/agent/metrics | grep -E "consul.(anti_entropy|sync)"
# Tail agent logs for RPC, TLS, or ACL errors
journalctl -u consul -f --since "10 min ago" | grep -iE "rpc|tls|x509|permission|anti_entropy"
On a server, run:
# Leader identity and Raft peer count
consul operator raft list-peers
# Server FD consumption
ls /proc/$(pgrep -x consul)/fd | wc -l
cat /proc/$(pgrep -x consul)/limits | grep "Max open files"
# How many client RPC connections is this server holding?
ss -tnp '( sport = :8300 )' | wc -l
How to diagnose it
- Confirm the failure is RPC, not gossip. From the affected agent,
consul membersmust show the server nodes asalive. If gossip itself is partitioned, you are looking at a different problem. See Consul gossip flapping or Consul serf queue backlog. - Localize the scope. One agent points at host-level network, cert, or ACL. Many agents in the same subnet point at a firewall or route change. Many agents across subnets point at the server side.
- Verify the RPC port end to end. From the agent,
nc -zv <server-ip> 8300. A timeout or refused connection narrows the cause to network or server handler. - Inspect the agent’s known server list.
consul infoshowsknown_servers. Zero known servers means the agent has lost its server discovery path. This happens when servers are replaced simultaneously with new IPs and the agent’s cached addresses are stale. - Read the agent logs for the failure class. The error string tells you which cause you are dealing with:
i/o deadline reachedorconnection refused: network or server handler.x509: certificate is valid for ...: TLS hostname mismatch.Permission denied: ACL.No known Consul servers: empty server list.
- Check server-side capacity. If many agents fail at once, the servers are the bottleneck. Check FD usage, goroutine count, and
consul.runtime.sys_fd_usedagainst the configured limit. Check whetherrpc_max_conns_per_clientis configured and whether per-client connection caps are being hit. - Check anti-entropy sync success on the agent. Sustained non-zero
consul.anti_entropyfailure rate, or sync latency well above the configured interval, confirms that the catalog is drifting because of the RPC break.
Metrics and signals to monitor
| Signal | Why it matters | Warning sign |
|---|---|---|
consul.client.rpc.failed rate | Direct counter of failed agent-to-server RPCs | Any sustained non-zero rate on any agent |
consul.client.rpc.exceeded rate | Agent-side rate limiter drops RPCs before they leave | Any sustained non-zero rate; correlates with limits misconfiguration |
consul.client.rpc total rate | Baseline RPC attempt rate; denominator for failure ratio | Sudden drop suggests the agent stopped attempting (no known servers) |
consul.anti_entropy failure rate and latency | Confirms catalog drift from the agent side | Failure rate above zero; latency well above the sync interval |
consul.serf.lan.members alive count | Gossip health; should remain stable while RPC fails | If this also drops, you have a gossip problem, not just RPC |
consul.runtime.sys_fd_used on servers | Server-side capacity that gates RPC accept | Sustained growth toward ulimit -n |
known_servers in consul info | Whether the agent can find any server at all | Zero |
Raft leadership and consul.raft.state.leader | Ruling out server-side consensus failure | Multiple elections; see Consul leader election storm |
For the fuller signal list, see Consul monitoring maturity model.
Fixes
Firewall asymmetry (8301 open, 8300 blocked)
The most common cause. A security-group, host firewall, or network policy change keeps 8301 open for gossip but drops 8300 for RPC.
- Confirm with
nc -zv <server-ip> 8300from the agent host. - Compare against the working baseline. If only the agent’s subnet is affected, the change is scoped to that path.
- Open TCP 8300 from client agents to server nodes in the direction the connection is initiated.
- Document the ports together so the next change does not split them. Consul requires 8300 for server RPC and 8301 (TCP and UDP) for LAN gossip as a pair.
Server RPC handler exhaustion
When servers run low on file descriptors, new RPC connections are refused. The client sees i/o deadline reached or connection reset by peer.
- Check
consul.runtime.sys_fd_usedand compare againstulimit -nfor the Consul process. HashiCorp recommends a high FD ceiling for production servers. - Check for connection leaks:
ss -tnp '( sport = :8300 )'connection count vs agent count. A server holding tens of thousands of connections from a handful of agents indicates a leak in those agents. - Raise
LimitNOFILE(systemd) orulimit -nand restart the server during a maintenance window. This is disruptive and drops in-flight RPC connections. - Investigate the leak separately. Common sources are consul-template blocking queries, leaked watches, and service mesh xDS streams.
TLS certificate mismatch
With verify_server_hostname = true in the tls.internal_rpc block, the agent validates that the server certificate is valid for server.<datacenter>.consul.<domain>. A cert valid for a different name produces x509: certificate is valid for X, not server.dc1.consul.example.com.
- Pull the cert the agent is presenting or trusting and inspect SANs:
openssl x509 -in <cert> -noout -text | grep -A1 "Subject Alternative Name". - Confirm the cert was issued with the Consul-internal RPC naming convention, not a generic service DNS name.
- Re-issue and redistribute the cert. Rotating certs on servers without also rotating on agents (or vice versa) is the typical trigger.
- Verify
verify_incomingandverify_outgoingare consistent across the cluster. Mixed modes produce confusing partial failures.
ACL permission denied
The agent has a token but the token lacks permission for a specific RPC method. The classic signature is Coordinate.Update failing repeatedly because the token cannot write coordinates.
- Pull the agent’s token and check the attached policies.
- Confirm the token grants
service:write(or the equivalent for what the agent registers),node:write, and coordinate-write permissions. - If the failure started after an ACL policy change, roll back the policy first, then tighten deliberately.
- Distinguish from token replication lag in federated DCs. In a secondary DC, a recently created token may not have replicated yet.
No known servers
The agent has nobody to dial. Logs show No known Consul servers and consul info reports known_servers: 0.
- Common cause: all servers were replaced with new IPs (new subnets, ASG replacement, redeploy) and the agent’s cached server list is stale.
- Trigger a re-join: add
retry_joinpointing at the new server addresses, or restart the agent so it re-discovers via gossip. - Brief blips during rolling server restarts are normal. Persistent zero is not.
Agent-side rate limiter
If the climbing counter is consul.client.rpc.exceeded rather than consul.client.rpc.failed, the agent’s limits configuration is dropping RPCs locally.
- Inspect the
limitsblock on the affected agent. - Compare the configured RPC rate and burst against the agent’s actual workload (number of services, checks, watches).
- Tune upward or remove the limit if it was set defensively without considering anti-entropy spikes after recovery.
Prevention
- Alert on sustained non-zero
consul.client.rpc.failedon every agent, not just servers. Server-side dashboards do not show this signal. It only exists on the agent. - Alert on
consul.client.rpc.exceededseparately. Different cause, different fix, same user-visible symptom. - Treat ports 8300 and 8301 as a pair in firewall policy. Any change to one must review the other.
- Monitor server FD usage with low thresholds. Page at 80% of
ulimit -n, plan at 60%. FD exhaustion is cliff-edge and cascades into RPC refusal across the fleet. - Run cert rotation as a coordinated procedure, not a server-only task. Test that agent-trusted certs validate
server.<dc>.consul.<domain>before rollout. - Periodically compare local agent state with catalog state. For a sample service, query both
/v1/agent/serviceson the agent and/v1/catalog/service/<name>on a server. Persistent divergence indicates the RPC pipeline is not keeping up even ifconsul.client.rpc.failedis quiet.
How Netdata helps
- Per-second collection of
consul.client.rpc.failed,consul.client.rpc, andconsul.client.rpc.exceededon every agent lets you see the failed counter climb before anti-entropy lag becomes user-visible. - Correlate agent RPC failures with server-side
consul.runtime.sys_fd_used, goroutine count, and Raft commit time on the same timeline to localize the cause in seconds. - Composite alerts pair
consul.client.rpc.failed > 0with healthyconsul.serf.lan.membersto surface the silent catalog staleness signature directly, rather than waiting for downstream consumer complaints. - Per-agent dashboards make it cheap to spot the difference between one host with a bad cert and a whole subnet behind a bad firewall rule.
Related guides
- Consul gossip encryption key mismatch
- Consul gossip flapping
- Consul serf queue backlog
- Consul gossip storm after mass recovery
- How Consul actually works in production
- Consul leader election storm
- Consul monitoring checklist
- Consul monitoring maturity model
- Consul “No cluster leader”
- Consul raft commitTime high
- Consul Raft data directory full
- Consul raft lastContact rising






