Error Medic

Consul Connection Refused: Complete Troubleshooting Guide

Fix 'consul connection refused' errors fast. Covers agent down, wrong ports, firewall rules, TLS mismatches, and ACL token issues with real commands.

Last updated:
Last verified:
1,932 words
Key Takeaways
  • Root cause 1: Consul agent is not running or crashed — verify with systemctl status consul and check logs in /var/log/consul/
  • Root cause 2: Incorrect bind address or port — Consul defaults to 127.0.0.1:8500 for HTTP; if the agent binds to a different interface, clients connecting to localhost will be refused
  • Root cause 3: Firewall or security-group rules blocking TCP 8500 (HTTP), 8501 (HTTPS), 8300 (RPC), or 8600 (DNS)
  • Root cause 4: TLS/ACL misconfiguration — HTTPS-only clusters refuse plain HTTP connections with a TCP RST that manifests as connection refused
  • Quick fix: Run consul agent -dev on a workstation to isolate whether the issue is config vs. network, then apply the targeted fix from the comparison table below
Fix Approaches Compared
MethodWhen to UseTimeRisk
Restart consul systemd serviceAgent is stopped or crashed; logs show exit code< 1 minLow — service restart only
Fix bind_addr / client_addr in consul.hclAgent starts but only listens on 0.0.0.0 or 127.0.0.1 while clients need a LAN IP5 min + reloadLow — requires config reload
Open firewall ports (iptables / nftables / AWS SG)Agent is running but remote hosts can't reach port 8500/83015–15 minMedium — exposes port; scope rules tightly
Switch CONSUL_HTTP_ADDR to HTTPS + cert trustCluster enforces TLS; plain HTTP connections are refused15–30 minLow if certs already exist
Generate and export ACL bootstrap tokenHTTP returns 200 but RPC calls return 'permission denied'; agent refuses connections after ACL enforcement10 minMedium — token material is sensitive
Roll back to previous Consul versionConnection refused started after an upgrade; no config changed20–40 minHigh — reverting may affect data

Understanding the "Connection Refused" Error in Consul

When you see a message like:

Get "http://127.0.0.1:8500/v1/status/leader": dial tcp 127.0.0.1:8500: connect: connection refused

or from the CLI:

Error querying agent: Get "http://127.0.0.1:8500/v1/agent/self": dial tcp 127.0.0.1:8500: connect: connection refused

your TCP SYN to Consul's HTTP port received a RST/ACK — meaning nothing is listening on that socket. This is distinct from a timeout (firewall drop) or a 403 Forbidden (ACL). Connection refused means the OS actively rejected the connection.


Step 1: Confirm Whether the Consul Agent Is Running

# systemd-managed systems
systemctl status consul

# Or for non-systemd
pgrep -a consul
ps aux | grep consul

If systemctl status consul shows Active: inactive (dead) or failed, start it:

systemctl start consul
journalctl -u consul -n 100 --no-pager   # inspect why it died

Common crash reasons found in journals:

  • Error parsing config: ... — invalid HCL/JSON in /etc/consul.d/
  • Failed to start Raft: ... — corrupted data dir; may need consul data-dir cleanup
  • Address already in use — another process on port 8500; find it with ss -tlnp | grep 8500

Step 2: Verify the Listening Address and Port

Even when the agent is running, it may not be listening where your client expects:

# Show all sockets Consul is bound to
ss -tlnp | grep consul

# Or with lsof
lsof -i -P -n | grep consul

Expected output for a default dev-mode agent:

TCP  127.0.0.1:8500   LISTEN   (consul)
TCP  127.0.0.1:8600   LISTEN   (consul)

If the agent binds only to 127.0.0.1 but your application runs in a container or on a different host, you will get connection refused on the LAN IP. Fix by editing /etc/consul.d/consul.hcl:

# /etc/consul.d/consul.hcl
client_addr = "0.0.0.0"          # listen on all interfaces for HTTP/DNS
bind_addr   = "{{ GetPrivateIP }}"  # bind RPC/gossip to the primary LAN IP

Then reload:

consul reload   # or: kill -HUP $(pgrep consul)
systemctl reload consul

Step 3: Check Firewall and Network Path

Consul uses several ports. All must be reachable between the relevant nodes:

Port Protocol Purpose
8500 TCP HTTP API & UI
8501 TCP HTTPS API (if TLS enabled)
8502 TCP gRPC (Consul Connect)
8300 TCP Server RPC
8301 TCP+UDP LAN Serf gossip
8302 TCP+UDP WAN Serf gossip
8600 TCP+UDP DNS
# From the client machine, test reachability
nc -zv <consul-server-ip> 8500
traceroute -T -p 8500 <consul-server-ip>

# On the server: check iptables
iptables -L INPUT -n --line-numbers | grep -E '8500|8301|8300'

# Quick allow rule (scope this to your CIDR in production)
iptables -A INPUT -p tcp --dport 8500 -s 10.0.0.0/8 -j ACCEPT

For AWS, GCP, or Azure security groups, add an inbound rule for TCP 8500 scoped to your VPC CIDR — never 0.0.0.0/0 unless behind a VPN.


Step 4: Rule Out TLS/HTTPS Misconfiguration

If your cluster has verify_incoming = true or https_port = 8501 in config but your client is pointing at http://..., the TLS handshake never completes and the kernel closes the connection — appearing as "connection refused" to application-layer code.

# Does the server speak TLS on 8501?
openssl s_client -connect <consul-ip>:8501 -CAfile /etc/consul.d/consul-ca.pem

# Export env vars to switch the CLI to HTTPS
export CONSUL_HTTP_ADDR="https://<consul-ip>:8501"
export CONSUL_CACERT="/etc/consul.d/consul-ca.pem"
export CONSUL_CLIENT_CERT="/etc/consul.d/client-cert.pem"
export CONSUL_CLIENT_KEY="/etc/consul.d/client-key.pem"
consul members   # should succeed now

Step 5: Validate ACL Bootstrap State

If ACLs are enabled but no bootstrap token exists, the agent enters a degraded mode where API connections may be actively refused or return 403. Check:

consul acl bootstrap
# If you see: "The ACL system is already bootstrapped."
# you need an operator token. Retrieve from a peer server's log or Vault.

# Export token and test
export CONSUL_HTTP_TOKEN="<your-management-token>"
consul members

Step 6: Consul in Kubernetes

For Helm-deployed Consul, connection refused commonly means the service endpoint isn't exposed or the pod isn't ready:

# Check pod status
kubectl get pods -n consul

# Describe a crashing pod
kubectl describe pod consul-server-0 -n consul

# Port-forward to test locally
kubectl port-forward svc/consul-ui 8500:80 -n consul
curl http://127.0.0.1:8500/v1/status/leader

# Check service endpoints
kubectl get endpoints consul-server -n consul

Missing endpoints means the readiness probe is failing — usually a bad TLS secret or wrong datacenter name in the Helm values.


Step 7: Confirm the Fix

curl -s http://127.0.0.1:8500/v1/status/leader
# Expected: "10.0.1.5:8300"  (the leader's address as a JSON string)

consul members
# Should list all agents with Status=alive

consul monitor -log-level=debug
# Watch live logs; Ctrl-C to exit

Frequently Asked Questions

bash
#!/usr/bin/env bash
# consul-diagnose.sh — Run on the host where connection refused occurs
# Usage: bash consul-diagnose.sh [consul-target-ip] [consul-http-port]

TARGET_IP="${1:-127.0.0.1}"
HTTP_PORT="${2:-8500}"

echo "===== Consul Connection Refused Diagnostic ====="
echo "Target: ${TARGET_IP}:${HTTP_PORT}"
echo ""

# 1. Is the consul process running?
echo "[1] Consul process check:"
pgrep -a consul && echo "  -> Process found" || echo "  -> NO consul process running"
echo ""

# 2. What is the consul agent listening on?
echo "[2] Open sockets for consul:"
ss -tlnp 2>/dev/null | grep consul || echo "  -> No consul sockets found (ss)"
lsof -i -P -n 2>/dev/null | grep consul || true
echo ""

# 3. Is anything on the target port at all?
echo "[3] Port ${HTTP_PORT} listener check:"
ss -tlnp | grep ":${HTTP_PORT}" || echo "  -> Nothing listening on ${HTTP_PORT}"
echo ""

# 4. Network reachability
echo "[4] TCP reachability test (nc):"
nc -zv -w 3 "${TARGET_IP}" "${HTTP_PORT}" 2>&1 && echo "  -> Port OPEN" || echo "  -> Port REFUSED or TIMEOUT"
echo ""

# 5. Firewall rules that might block the port
echo "[5] iptables rules touching port ${HTTP_PORT}:"
iptables -L INPUT -n --line-numbers 2>/dev/null | grep "${HTTP_PORT}" || echo "  -> No explicit iptables rule found (default policy applies)"
echo ""

# 6. Attempt HTTP API call
echo "[6] HTTP API call to /v1/status/leader:"
curl -sf --max-time 5 \
  "http://${TARGET_IP}:${HTTP_PORT}/v1/status/leader" \
  && echo "" || echo "  -> curl failed (see error above)"
echo ""

# 7. Attempt HTTPS API call (if TLS might be enabled)
echo "[7] HTTPS API call to /v1/status/leader (ignoring cert for diagnosis):"
curl -sk --max-time 5 \
  "https://${TARGET_IP}:8501/v1/status/leader" \
  && echo "" || echo "  -> HTTPS also failed"
echo ""

# 8. Recent consul service logs
echo "[8] Last 20 consul journal lines:"
journalctl -u consul -n 20 --no-pager 2>/dev/null || echo "  -> journalctl not available or consul unit not found"
echo ""

# 9. consul.hcl bind config snippet
echo "[9] Consul config bind/client addresses:"
grep -r -E '(bind_addr|client_addr|ports|http|https)' /etc/consul.d/ 2>/dev/null || echo "  -> /etc/consul.d/ not found or no matching config"
echo ""

echo "===== Diagnostic complete ====="
echo "Next steps:"
echo "  If [1] shows no process: systemctl start consul"
echo "  If [3] shows wrong IP: fix client_addr in /etc/consul.d/consul.hcl"
echo "  If [4] shows TIMEOUT (not refused): open firewall port ${HTTP_PORT}"
echo "  If [7] succeeds but [6] fails: switch to HTTPS with CONSUL_HTTP_ADDR=https://...:8501"
E

Error Medic Editorial

Error Medic Editorial is a team of senior DevOps and SRE engineers with combined experience across HashiCorp tooling, Kubernetes, and large-scale distributed systems. We write production-tested troubleshooting guides based on real incident post-mortems and community issue trackers.

Sources

Related Articles in Consul

Explore More DevOps Config Guides