Error: connect ECONNREFUSED 10.0.4.22:5432

Short answer

The connection reached a host and that host said no. ECONNREFUSED is a TCP reset from a live machine with nothing listening on that port — which is genuinely good news, because it proves DNS, routing, and the network path all worked.

What it means

Of the four ways a network call can fail on Lambda, this is the one that tells you the most. ECONNREFUSED is a TCP reset: the SYN packet arrived at a live machine, the kernel there found nothing bound to that port, and it sent back a refusal. Every layer below the service — DNS, routing, NAT, security groups, network ACLs — did its job.

That eliminates most of the VPC problem space in one reading. If security groups were blocking the traffic you would get ETIMEDOUT, because a dropped packet produces silence rather than a refusal. If the name were wrong you would get ENOTFOUND. Getting a reset means the address is right, the path is open, and the only thing missing is a listener.

The single most common instance on Lambda is 127.0.0.1. A Lambda execution environment contains your function and the runtime — no database, no cache, no sidecar. Code that ran under Docker Compose, or on a server where Postgres happened to be local, carries a connection string that was perfectly correct in its original home and refers to nothing here. The error is immediate and the address in the message names the mistake outright.

The other case worth recognising is failover. During an RDS or ElastiCache failover the old host stays up while the service stops accepting connections, and DNS takes a moment to move. In that window every function gets a refusal, all at once, and then the problem disappears on its own. A burst of ECONNREFUSED across every concurrent execution followed by clean recovery is that pattern — and it is a case for a short bounded retry rather than for changing any configuration.

Depends

CloudWatch’s Errors metric: Whether CloudWatch’s Errors metric counts this depends on whether the error escaped your handler, which the log line alone does not settle. Counted only when the error escapes the handler. LogStitch classified the example below from its log level rather than an extracted error type, so it reports the failure as caught.

What it looks like in CloudWatch

This is the shape the failure arrives in: the lines of one invocation scattered among everything else the log group received at the same moment.

CloudWatch Logs Before

7 raw lines, in the order CloudWatch delivered them.

2026-08-30T09:02:44.114Z START RequestId: 91c4e7b2-5a38-4f01-bd26-7e0c9a3f1b58 Version: $LATEST
2026-08-30T09:02:44.118Z 91c4e7b2-5a38-4f01-bd26-7e0c9a3f1b58 INFO Opening ledger connection
2026-08-30T09:02:44.126Z 91c4e7b2-5a38-4f01-bd26-7e0c9a3f1b58 ERROR Error: connect ECONNREFUSED 10.0.4.22:5432
at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1555:16)
at Client._connect (/var/task/node_modules/pg/lib/client.js:88:11)
2026-08-30T09:02:44.402Z END RequestId: 91c4e7b2-5a38-4f01-bd26-7e0c9a3f1b58
2026-08-30T09:02:44.402Z REPORT RequestId: 91c4e7b2-5a38-4f01-bd26-7e0c9a3f1b58 Duration: 288.09 ms Billed Duration: 289 ms Memory Size: 512 MB Max Memory Used: 104 MB Status: error

LogStitch After

The same lines, grouped into the invocation they belong to.

Error91c4e7b2-5a38-4f01-bd26-7e0c9a3f1b58dur 288msbilled 289msmem 104/512MBlogs 5
  1. 09:02:44.114PLAT
    START RequestId: 91c4e7b2-5a38-4f01-bd26-7e0c9a3f1b58 Version: $LATEST
  2. 09:02:44.118INFO
    INFO	Opening ledger connection
  3. 09:02:44.126ERROR
    ERROR	Error: connect ECONNREFUSED 10.0.4.22:5432
        at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1555:16)
        at Client._connect (/var/task/node_modules/pg/lib/client.js:88:11)
    3 lines
  4. 09:02:44.402PLAT
    END RequestId: 91c4e7b2-5a38-4f01-bd26-7e0c9a3f1b58
  5. 09:02:44.402PLAT
    REPORT RequestId: 91c4e7b2-5a38-4f01-bd26-7e0c9a3f1b58	Duration: 288.09 ms	Billed Duration: 289 ms	Memory Size: 512 MB	Max Memory Used: 104 MB	Status: error
Error
Status
288ms
Duration
289ms
Billed
104/512MB
Memory
80%
Headroom
No
Cold start
LogLevelError
Error type

The panel on the right is generated by running the excerpt on the left through the same parser that powers the free web stitcher — it is what the tool actually produces for this input, not an illustration of it.

How to confirm it from the logs

The address and port in the message are the whole diagnosis. 127.0.0.1 or localhost means the code is trying to reach something in its own container — there is nothing else there, and this is almost always code carried over from a Docker or local development setup. A private address means the host is reachable and the service is not listening, or is listening on a different port.

Contrast it with the alternatives, because the distinction is precise and useful. ECONNREFUSED is immediate — the reset comes back in milliseconds. ETIMEDOUT takes seconds and means nothing answered at all, which points at routing or security groups. ENOTFOUND means the name never resolved. Getting a refusal means you are further along than either of the others.

Causes, most likely first

1

The code is connecting to localhost

How to confirm

Look for 127.0.0.1 or localhost in the address. A Lambda execution environment runs your handler and nothing else — no sidecar database, no local Redis, no Docker Compose peer. Code moved from a containerised environment frequently keeps a connection string that was correct there and cannot work here.

2

The service is listening on a different port

How to confirm

Compare the port in the message against the service's actual listener. A refusal means the host is up, so an off-by-one in a port number or a default assumed for the wrong engine — 5432 for Postgres against a MySQL instance on 3306 — produces exactly this.

3

The database or service is down, restarting, or failing over

How to confirm

Check whether the refusals cluster in time across many invocations rather than affecting one request. A simultaneous burst across every concurrent execution is a server-side event; the host is up enough to send resets but the service on it is not accepting connections.

4

The connection is going to the wrong host entirely

How to confirm

Check the address against the resource you intend. A stale private IP, a reader endpoint where a writer was meant, or a hostname resolving to a decommissioned instance all reach something that refuses rather than something that answers.

Fixes

Fix 1

Point the function at a real endpoint rather than a local one

There is no localhost service in a Lambda. Move the dependency to a managed endpoint and configure it through an environment variable, so the same code works in both places.

js// Carried over from docker-compose — nothing listens here in Lambda.
// const redis = createClient({ url: "redis://localhost:6379" });

const redis = createClient({ url: process.env.REDIS_URL });
Fix 2

Confirm what the host is actually listening on

A refusal proves the host is reachable, so the question is narrowly about the port and the service. Reading the endpoint back from the resource itself removes the guesswork.

bashaws rds describe-db-instances --db-instance-identifier orders-prod \
  --query 'DBInstances[0].Endpoint'
Fix 3

Retry across a failover rather than failing the invocation

During an RDS failover the old host refuses connections for a short window before DNS moves. A short bounded retry rides through it; an unbounded one just burns your timeout.

jsasync function connectWithRetry(attempts = 3) {
  for (let attempt = 1; attempt <= attempts; attempt += 1) {
    try {
      return await pool.connect();
    } catch (error) {
      if (error.code !== "ECONNREFUSED" || attempt === attempts) throw error;
      await new Promise((r) => setTimeout(r, 2 ** attempt * 100));
    }
  }
}

Also seen as

The same underlying failure, worded differently by a different runtime, SDK version, or logging layer. All of these land here — there is no separate page for each phrasing.

connect ECONNREFUSED 127.0.0.1:6379ConnectionRefusedError: [Errno 111] Connection refusedjava.net.ConnectException: Connection refusedlambda connection refusedlambda econnrefused rds

Errors that show up alongside this one, or that people mistake for it.

References

LogStitch finds this automatically, across every invocation in your account.

Paste a log excerpt into the free web stitcher and see it grouped, classified, and measured in your browser — nothing is uploaded. Or run the Mac app against your own AWS profiles and get the same view over every function you own.