curl Error: '(7) Failed to connect ... Connection refused' — Cause, Fix, and Troubleshooting Guide
Fix curl: (7) Failed to connect to api.example.com port 443: Connection refused — DNS resolved but TCP connect failed: down service, wrong port, firewall.
- #automation
- #troubleshooting
- #curl
Fixing errors like this? Get 500 free DevOps AI prompts
500 copy-paste AI prompts for the stack you actually run — one PDF, free.
Overview
curl exit code 7 means the name resolved to an IP, curl opened a TCP connection to that IP:port, and the connection did not complete. Unlike code 6 (DNS), curl knows where to go; the problem is at the transport layer. The message includes the reason and how long it took:
$ curl -v https://api.example.com/health
* Trying 10.0.4.21:443...
* connect to 10.0.4.21 port 443 failed: Connection refused
* Failed to connect to api.example.com port 443 after 2050 ms: Connection refused
curl: (7) Failed to connect to api.example.com port 443 after 2050 ms: Connection refused
Connection refused (immediate RST) means nothing is listening on that port or a firewall is actively rejecting — the same TCP condition that surfaces as ECONNREFUSED in Node.js and other runtimes. It is distinct from a timeout (code 28), where packets are silently dropped and curl hangs before giving up. Refused is fast and definitive; timed-out is slow and ambiguous.
Symptoms
curl: (7) Failed to connect to <host> port <port> after N ms: Connection refused.- curl prints
Trying <ip>...(so DNS worked) then fails fast — usually well under a couple seconds. nc -zv <host> <port>reportsConnection refusedtoo.- The same host resolves fine (
getent hostsreturns an IP) — separating this from a code 6 DNS failure.
curl -sS -o /dev/null -w '%{http_code}\n' https://api.example.com/health; echo "exit: $?"
exit: 7
Common Root Causes
1. The target service is down
Nothing is bound to the port because the process crashed or never started.
# On the target host
ss -ltnp | grep ':443' || echo "no listener on 443"
no listener on 443
2. Wrong port
The service is healthy but listens elsewhere; the caller uses the wrong port (often a default assumption after a config change).
LISTEN 0 511 0.0.0.0:8443 users:(("api",pid=904,fd=7))
3. Firewall / security group sending REJECT
A REJECT rule (as opposed to DROP) returns an RST that curl reports as refused, even though the service is up.
sudo iptables -L INPUT -n | grep -E '443|REJECT'
REJECT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:443 reject-with icmp-port-unreachable
4. Service bound to loopback only
Listening on 127.0.0.1 accepts local calls but refuses anything from another host or container.
LISTEN 0 511 127.0.0.1:443 users:(("api",pid=904,fd=7))
5. A proxy is required but not used
The direct route is closed; traffic must go through an HTTP proxy that curl was not told to use.
How to Diagnose
Step 1: Confirm DNS is not the issue
getent hosts api.example.com
10.0.4.21 api.example.com
A resolved IP proves this is code 7 (connect) territory, not code 6 (DNS).
Step 2: Classify refused vs timeout with nc
nc -zv 10.0.4.21 443
nc: connect to 10.0.4.21 port 443 (tcp) failed: Connection refused
Instant “refused” = nothing listening or a REJECT rule. A hang that ends in “timed out” is a different problem (code 28 / DROP).
Step 3: Check for a listener on the target host
ss -ltnp | grep ':443'
systemctl status api --no-pager | head -5
no listener on 443
● api.service - API Active: failed (Result: exit-code) ...
Step 4: Verify the port and bind address match
ss -ltnp | grep api
LISTEN 0 511 127.0.0.1:8443 users:(("api",pid=904,fd=7))
Here the service is up but on 127.0.0.1:8443 — wrong bind address and wrong port versus a remote caller hitting :443.
Step 5: Rule out a firewall reject
sudo iptables -L INPUT -n | grep -E '443|REJECT'
# Cloud: inspect the security group inbound rules for the port
Fixes
If the service is down, restart it and confirm a listener:
sudo systemctl restart api
ss -ltnp | grep ':443'
LISTEN 0 511 0.0.0.0:443 users:(("api",pid=1201,fd=7))
If the port is wrong, point curl at the actual port:
curl -v https://api.example.com:8443/health
If it is bound to loopback, rebind to 0.0.0.0 (or the routable interface) and restart. If a firewall rejects, open the port in iptables or the security group. If a proxy is required, pass it explicitly:
curl -v --proxy http://proxy.example.com:3128 https://api.example.com/health
A completed connection returns a status line:
< HTTP/1.1 200 OK
What to Watch Out For
- Refused (code 7) is immediate; timed-out (code 28) hangs — do not apply a firewall-DROP fix to a refused error or vice-versa.
- The
after N msin the message is connect latency, not a timeout you configured; a small number confirms fast refusal. - A service on
127.0.0.1passes a local curl test but refuses every remote caller — always test from where the automation actually runs. - REJECT firewall rules masquerade as “service down”; check iptables/security groups before restarting a healthy service.
- This is the curl-side view of the same TCP RST that appears as
ECONNREFUSEDin webhook and job runtimes.
Related Guides
- connect ECONNREFUSED — webhook target connection refused
- curl (28) Operation timed out
- curl (6) Could not resolve host
Get 500 Battle-Tested DevOps AI Prompts — Free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.