ECONNRESET & 'socket hang up' — why connections reset and how to fix it
Quick answer: ECONNRESET ("read ECONNRESET" / "socket hang up") means the remote side closed the TCP connection abruptly while your app was using it. It's usually a reused keep-alive socket the server already dropped, an upstream that restarted mid-request, or a proxy idle-timeout. Make the client resilient: retry idempotent requests, and keep your client's idle timeout shorter than the server's.
What the error looks like
It surfaces on the reading side of a connection that vanished:
Error: read ECONNRESET
at TCP.onStreamRead (node:internal/stream_base_commons:217:20)
errno: -104, code: 'ECONNRESET', syscall: 'read'
# via an HTTP client it often reads as:
Error: socket hang up (code: 'ECONNRESET')
"Reset" is different from "refused": the connection was established, then the other end tore it down. That points at a connection that went stale or an upstream that died, not a wrong address.
Why it happens
A reused keep-alive socket went stale
Your client reused a pooled connection the server had already closed, so the first write resets.
The upstream restarted mid-request
A deploy, scale-down, or crash on the other side severed connections that were in flight.
A proxy idle-timeout fired
A load balancer or proxy closed an idle connection your client still thought was open.
The server dropped you on purpose
A rate limiter, max-body guard, or WAF reset the connection instead of replying.
Diagnose it in three steps
Find which host resets
# Log the request target on error so you know who hung up
# Is it always the same upstream? That narrows it fast.First request or only reused?
# If it only fails on the 2nd+ request to a host, it's stale keep-alive.
# If it fails right when you deploy the upstream, it's the restart.Compare the timeouts
# Server idle timeout must be >= client keep-alive timeout,
# or the client will keep grabbing sockets the server just closed.Make the client expect dead sockets
You can't stop a peer from ever closing a connection — so handle it. Keep idle sockets short-lived and retry safe requests:
const http = require('http');
const agent = new http.Agent({
keepAlive: true,
// give up on an idle socket BEFORE the upstream does
timeout: 30_000,
});
// Retry only idempotent requests (GET/PUT/DELETE), with backoff.
// Never blindly retry a POST that may have already been processed.
Deploys that drain instead of reset
A large share of production ECONNRESETs come from the upstream restarting mid-request on deploy. Infraveil is a backend operations control plane that runs on your own servers: its agent drains connections on the old instance before stopping it, and only shifts traffic to a health-checked new one — so a rollout doesn't sever live sockets. Every deploy is approval-gated and recorded, with one-click rollback.
Frequently asked questions
What does ECONNRESET mean?
The remote end abruptly closed an established TCP connection (a "connection reset by peer"). Your side was mid-read or mid-write when the socket disappeared.
Is ECONNRESET my fault or the server's?
Often neither is "broken" — it's a stale pooled connection or an upstream that restarted. The durable fix lives on the client: short idle timeouts plus retries for idempotent requests.
How do I fix 'socket hang up' in axios?
Use a keep-alive agent with a timeout shorter than the upstream's, and add retry-with-backoff (e.g. axios-retry) for safe methods. Investigate the upstream if it correlates with its deploys.
ECONNRESET vs ECONNREFUSED?
Refused means nothing accepted the connection (service down / wrong port). Reset means a connection was established and then torn down by the other side.