Notebook

Connection refused vs connection reset vs connection timed out — which one means what

Three error phrases that look similar but point at completely different failures. One means the server doesn't exist; one means it killed your conversation mid-sentence; one means it ghosted you. Here's how to tell them apart and what each tells you to do.

StatusDetectorMay 12, 20269 min read

If you've ever pasted a URL into a curl command or a browser and gotten back one of these three errors, you've probably also been confused about which one means what. They sound similar, they happen in similar contexts, and the OS-level error names (ECONNREFUSED, ECONNRESET, ETIMEDOUT) make sense only if you know what each TCP state transition looks like. This is the field guide.

What each one is, at the TCP level

Forget the OS error names for a second. Picture the three-way handshake every TCP connection starts with:

  1. Client → Server: SYN ("can we talk?")
  2. Server → Client: SYN-ACK ("yes")
  3. Client → Server: ACK ("great, here's my data")

The three errors are about what came back during or after that exchange:

The difference matters: refused is fast (you get an answer in milliseconds), timed out is slow (you wait the full timeout, usually 10-30 seconds), and reset can be either — it depends on when the server killed the connection.

Connection refused

You attempted to open a TCP connection and the server immediately replied with an RST packet. The server's machine is up, the IP is routable, but the requested port has nothing listening on it.

The most common causes, in rough order:

  • You're connecting to the wrong port. You meant 443; you typed 80; the server only listens on 443. Or vice versa.
  • The service crashed or hasn't started. The host is up, but the app process is down. A common state right after a deploy.
  • A firewall is rejecting (not dropping) the packet. Firewalls can either drop a packet silently (you see a timeout) or send back an RST (you see refused). Refused happens when the firewall is configured to be polite about saying no — many corporate firewalls do this for internal IPs.
  • You're inside a container and the port isn't published. The app is listening inside the container but the container engine never mapped the port out to your local machine.

The diagnostic is fast: curl http://host:port/ returns "Connection refused" within milliseconds. That's the tell. If the same curl against the host's :22 (or any port you know is open) succeeds, the host is reachable and the issue is port-specific.

Connection reset

This one is sneaky because it has two different causes that look identical from outside.

The clean case: the server explicitly killed the connection with an RST packet, mid-conversation. The OS error is ECONNRESET. The application on the server decided your request was bad, finished too slowly, or violated some protocol invariant.

Common application-level causes:

  • The server reached its concurrency limit and killed older connections. Web servers under load do this.
  • The server hit a request timeout and bailed. The app was processing your request but decided to give up.
  • You tried to send data after the server already responded and closed. Classic in HTTP/1.1 keep-alive misuse.
  • A WAF or DDoS-protection layer decided your request looked malicious. Cloudflare, AWS Shield, etc. can issue an RST when they don't want to give you a polite HTTP error.

The dirty case: a middlebox between you and the server (a load balancer, a stateful firewall, a NAT gateway) ran out of state and killed your connection without telling either side. The server never sent an RST — but you see one because the middlebox forged it on the server's behalf. This is incredibly common on long-lived idle connections behind cloud load balancers.

If you're seeing resets on connections that have been idle for a while, the dirty case is your culprit and the fix is usually a TCP keepalive every 30 seconds or so.

Connection timed out

The most ambiguous of the three, because nothing comes back at all. You sent a SYN, waited the full timeout, gave up.

The set of possible causes is wider than refused or reset:

  • The host is genuinely offline or has no network route. Your packets are going into the void.
  • A firewall is silently dropping packets (the "drop" rather than "reject" stance). Many security-conscious firewalls do this so attackers can't enumerate open ports.
  • The host is up but its TCP stack is so overloaded it can't handle new SYNs. Rare but happens during DDoS or massive traffic spikes.
  • You typed the wrong IP. Or the DNS for the hostname has gone stale and now resolves to a defunct IP.
  • Routing problem upstream. Somewhere between you and the destination, a transit provider is dropping the traffic on the floor.

Diagnostic: traceroute to the destination. If hops stop somewhere in the middle, you've found the broken router. If hops complete all the way but the destination still won't reply, the destination is dropping you specifically.

Long timeouts hurt because they delay every retry. If you can shorten the OS-level connect timeout in your client, do it — 30-second timeouts on production paths are an availability anti-pattern.

How they show up in real tools

Different tools report the same three states with different surface text. The OS error code is the only reliable identifier.

The error string varies; the underlying TCP signal is identical. Translate the surface text back to one of the three, then triage from this guide.

Fixing each one — the cheat sheet

When the failure isn't actually network

A trap worth flagging: TLS handshake failures often look like resets. If the TCP handshake completed but the TLS handshake didn't (mismatched cert, expired cert, unsupported cipher), some clients report this as a connection reset because the server killed the TLS layer with an RST. Always check whether the failure happens on port 443 specifically — if it does and port 80 works, you're looking at a TLS issue, not a TCP one.

The companion piece Reading SSL certificate errors walks through the TLS failure modes that masquerade as connection resets.

For an automated first pass on any of these failures, paste the URL into the Website Down Checker — it runs DNS resolution, TCP connect, and TLS handshake independently and tells you which layer failed.

Frequently asked

Why does my browser sometimes show ERR_CONNECTION_RESET when the site loads fine on retry?

Either the server is intermittently overloaded and killing connections under pressure, or a middlebox between you and the server has flaky state. Reload the page; if the issue persists across multiple retries, the server-side cause is real. If it goes away after one retry, you're probably seeing a transient middlebox reset.

Are timeouts always the server's fault?

No — they can be a client-side network issue, a routing problem in the middle, or genuinely the server. The traceroute test isolates which third of the path is broken. If traceroute completes but the connection still times out, the server is the most likely culprit.

How long should I wait before giving up on a connection?

The default OS-level connect timeout is often 30-120 seconds, which is far too long for any interactive workflow. Most production HTTP clients set a 5-10 second connect timeout. Anything longer just delays your retry without making success more likely.

StatusDetector

We check whether a website, app, API, or domain is working, broken, expired, parked, or permanently shut down. Free, no signup — run a check or open the shutdown radar.