Redis Connection Refused (ECONNREFUSED) (tested)
ECONNREFUSED means the TCP connection itself was rejected: either nothing is listening on that host and port, or a firewall actively refused it. It happens before Redis ever sees a command, so it is different from an auth error. We measured three clients (ioredis, redis, redis-cli) against a closed port and against a real Redis container we stopped and restarted mid-test.
1. What ECONNREFUSED means
ECONNREFUSED is an operating-system level TCP error, not a Redis error. The kernel on the target host received a SYN packet for a port with no process listening on it, and answered with a reset instead of a handshake. Redis never ran, Redis crashed, Redis is listening on a different port, or something else (a stale container, a reused port) is in the way.
This is distinct from an authentication failure. If Redis is up and listening but rejects your command, you get a Redis-level reply like NOAUTH, not a connection error. We measured both, see section 5.
2. Our test setup
We ran a real Redis 7.4.11 container (redis:7-alpine) via docker run --name forever-redistest -p 6380:6379 redis:7-alpine for the happy path and the live-reconnect test. For the closed-port tests we pointed clients at port 6381, which nothing was listening on.
$ docker run --rm -d --name forever-redistest -p 6380:6379 redis:7-alpine
$ docker exec forever-redistest redis-cli ping
PONG
Happy path confirmed first: ioredis against the live container fired connect then ready, and PING returned PONG.
3. The exact errors, three clients, same closed port
| Client | Error code | Exact message | What happens without custom handling |
|---|---|---|---|
| ioredis 6.0.0 | ECONNREFUSED | connect ECONNREFUSED 127.0.0.1:6381 | Emits a repeated 'error' event, auto-retries forever by default. Does not throw or crash the process. |
node-redis 6.3.0 (redis package) | ECONNREFUSED | connect ECONNREFUSED 127.0.0.1:6381 | Same: repeated 'error' events, built-in auto-retry, client.connect()'s promise stays pending while it keeps trying. No crash. |
| redis-cli (bundled in redis:7-alpine) | n/a (CLI text) | Could not connect to Redis at 127.0.0.1:6381: Connection refused | Prints the message, exits with code 1. One attempt, no retry. |
Both Node clients behave the same way under default settings: an unhandled 'error' listener would otherwise crash the process on the first attempt, but once you attach .on('error', ...), the client just keeps retrying in the background and never throws. We counted the retries for ioredis with no custom retryStrategy: 6 error events in 3 seconds, with growing gaps (4ms, 161ms, 410ms, 693ms, 1157ms, 2148ms after the first). That matches ioredis's documented default retryStrategy of Math.min(times * 50, 2000) ms between attempts, retried indefinitely unless you return null from your own strategy or call .disconnect().
4. Live test: stop the container, watch the client, restart it
We connected ioredis to the real container on port 6380, pinged it every 500 ms, then ran docker stop forever-redistest mid-loop, waited 4 seconds, then started a fresh container on the same port, with no code changes or reconnect call in between.
[+2521ms] ping #5 -> PONG
[+3029ms] event:close
[+3030ms] event:reconnecting, delay= 150
[+3183ms] event:error ECONNREFUSED "connect ECONNREFUSED 127.0.0.1:6380"
...
[+6855ms] event:reconnecting, delay= 3292
[+10150ms] event:connect
[+10153ms] event:ready
[+10154ms] ping #6 -> PONG
The moment the container stopped, ioredis fired close, then kept retrying with growing delays (150ms, 281ms, 347ms, 424ms, 814ms, 1795ms, 3292ms between tries). As soon as the new container was listening again, the very next retry succeeded: connect and ready fired and PING started returning PONG again, about 3.1 seconds after the container came back. We wrote zero reconnect logic; ioredis's default behaviour recovered on its own.
5. NOAUTH is a different error, not ECONNREFUSED
We set requirepass on the live container (redis-cli config set requirepass testpass123) and connected without credentials, to confirm this is a different failure mode than a refused connection.
| Client | Result |
|---|---|
| redis-cli | NOAUTH Authentication required. (exit 0 for the PING attempt itself; the reply is the error) |
| ioredis | Rejects with a ReplyError: NOAUTH HELLO must be called with the client already authenticated, otherwise the HELLO <proto> AUTH <user> <pass> option can be used to authenticate the client and select the RESP protocol version at the same time |
The TCP connection succeeded in both cases; Redis answered immediately with a Redis-protocol error, not a refused socket. If you see NOAUTH or WRONGPASS, the network path is fine and the fix is credentials (requirepass / -a / the client's password option), not anything in this guide.
6. Common real causes of ECONNREFUSED
- Redis isn't running yet, or crashed. Our closed-port test (section 3) is exactly this case: nothing listening, instant refusal.
- Wrong port. Default is 6379; a custom
portin redis.conf, a Docker-premap (like our 6380), or a typo in the client config all produce the same ECONNREFUSED if the client points at the wrong number. - App and Redis are in different Docker networks or hosts. A container on one Docker network can't reach a Redis container on another unless they share a network or Redis is published on the host. Per Docker's networking docs, not separately measured here: this usually also shows as ECONNREFUSED (if something else is listening on that port/host inside the app's network) or ETIMEDOUT/no route (if nothing answers at all) — see ETIMEDOUT for that variant.
- Redis bound to 127.0.0.1 only. If
bind 127.0.0.1is set and a client connects from another machine or container, the OS refuses the connection the same way as a closed port, because nothing is listening on the external interface. Per the Redis docs, not separately measured here. - Container stopped or restarting. Our live test (section 4) reproduced this directly: during the stop/restart window every attempt got ECONNREFUSED, then succeeded the instant the new process was listening.
7. How to handle it
- Always attach an
'error'listener. Both ioredis and node-redis will crash the process with an unhandled error on the very first failed attempt if you don't, even though they retry fine once you do. - Let the client's built-in retry do its job for transient drops (our test shows ioredis recovers alone). Only write custom reconnect code if you need to cap attempts or change the backoff.
- Confirm host and port independently:
redis-cli -h HOST -p PORT pingfrom the same network/container the app runs in. Its one-shot "Could not connect ... Connection refused" is the fastest way to confirm the problem is the socket, not your app's Redis client code. - If you get
NOAUTH/WRONGPASSinstead, the network is fine (section 5); fix credentials, not connectivity. - In Docker, check both containers are on the same network (
docker network inspect) and that the port is actually published if the client lives outside the Redis container's network.
If the connection succeeds but then drops repeatedly, see ECONNRESET. For the general cross-language version of this error, see ECONNREFUSED.
Frequently asked questions
What does ECONNREFUSED mean for Redis specifically?
Nothing answered on that host and port. The OS sent back a TCP reset instead of completing the handshake. We measured this by pointing ioredis, node-redis and redis-cli at a closed port: all three got ECONNREFUSED, none got a Redis-level reply, because Redis never saw the request.
Will my Node app crash when Redis is unreachable?
Only if you have no 'error' listener on the client. With one attached, we measured that both ioredis and node-redis just keep emitting 'error' events and retrying in the background by default; they don't throw or exit the process.
Does ioredis reconnect automatically when Redis comes back?
Yes, by default, with no code required. In our live test we stopped a running Redis container mid-session and restarted it 4 seconds later; ioredis kept retrying with growing delays and reconnected on its own about 3 seconds after the new container started listening.
Is NOAUTH the same problem as connection refused?
No. We measured NOAUTH by setting a password on a live container and connecting without one: the TCP connection succeeded and Redis replied with 'NOAUTH Authentication required.' That means the network path is fine; the fix is credentials, not anything related to ECONNREFUSED.
Redis is definitely running — why do I still get ECONNREFUSED?
The most common reasons we didn't have to simulate: wrong port (6379 vs a custom one), the app and Redis sitting in different Docker networks, or Redis bound to 127.0.0.1 while the client connects from elsewhere. Run redis-cli -h HOST -p PORT ping from the same place your app runs to isolate it.
Written with AI assistance. Measured on 2026-10-02 with Node.js 24.21.0, ioredis 6.0.0, node-redis (the "redis" package) 6.3.0, against a throwaway Redis 7.4.11 (redis:7-alpine, official image) container run via Docker. redis-cli is the one bundled in that same image. The "different Docker network" cause in section 6 is reasoned from how Docker networking works, not separately measured. PlainHeaders is our extension; curl, Node.js, Docker and redis-cli are free.