On this page
Why Does My Database Connection Time Out?
Connection timeouts come from four places: the pool is exhausted, the database's connection limit is reached, the network blocks the path, or the server is too busy to accept.
Quick answer
- A connection timeout is not the same as a query timeout: the application could not establish a connection at all.
- The most common cause is a connection pool whose connections are all in use, so new requests wait until they give up.
- The second is the database’s own connection limit, which is a hard ceiling shared by every client of that database.
- The third is the network: a firewall, security group, or wrong hostname that prevents reaching the port.
- The fourth is an overloaded server that cannot accept new connections in time — often a symptom of the first two.
Why does a database connection time out?
Because the connection could not be established within the client’s timeout. That is distinct from a query that runs too long after connecting, and the error message usually says which: a connection timeout mentions connecting, a statement timeout mentions the statement. The distinction matters because the fixes are different, and because a connection timeout often has nothing to do with the database’s own performance.
Four causes cover most cases. The application’s connection pool has no free connection, so the request waits in a queue. The database has reached its maximum connection count and refuses new ones. The network path is blocked or wrong. Or the database server is so busy that even accepting a connection takes longer than the timeout. The first two are by far the most common in small applications.
Step 1 — find which layer is refusing
Test the connection directly from the application’s host, with the same credentials and hostname the application uses. If a direct client connects instantly, the network is fine and the problem is in the application’s pool or in load. If it hangs or is refused, the problem is below the application — network, credentials, or the database’s capacity.
Then compare the pool’s configuration with what the system is doing. Most pool implementations expose the number of open, idle, and waiting connections, and the pattern that causes timeouts is unmistakable: open connections pinned at the maximum and a growing queue of waiters. That is exhaustion, and the fix is in how connections are held, released, and sized.
# Test the path directly, bypassing the application's pool.
psql "$DATABASE_URL" -c 'SELECT now(), count(*) FROM pg_stat_activity;'
nc -vz db.internal 5432 # is the port reachable at all?
# Postgres: how many connections, in which states, and what is the limit?
# psql: SELECT state, count(*) FROM pg_stat_activity GROUP BY state;
# psql: SHOW max_connections; SELECT count(*) FROM pg_stat_activity;
# Look for connections that are idle and holding a slot.
# psql: SELECT pid, state, now() - state_change AS idle_for, query
# FROM pg_stat_activity
# WHERE state = 'idle' AND now() - state_change > interval '5 minutes';Step 2 — fix pool exhaustion
Pool exhaustion is a lifecycle problem more often than a size problem. Connections are checked out and not returned — because an error path skips the release, because a transaction is left open, or because work is done while holding a connection instead of after releasing it. Raising the maximum connections without fixing that simply raises the ceiling and delays the timeout, while consuming more of the database’s connection budget.
The other common shape is a pool that is genuinely too small for the concurrency. If the application handles two hundred concurrent requests and each holds a connection for a database round trip, the pool needs to be sized to the number of simultaneous queries rather than the number of requests. Servers between the application and the database, such as a transaction-pooling connection pooler, exist to make many application connections share few database connections — which also fixes the limit problem in the next step.
Step 3 — respect the database’s connection limit
Every database has a maximum connection count, and every client of that database shares it. In horizontal architectures this is where things break: four application instances each with a pool of twenty consume eighty connections, and adding a fifth, or a migration, or an admin session, crosses the limit. The failure is not graceful — new connections are refused or queued — and it arrives suddenly as the system scales.
Budget connections deliberately. Decide the maximum, divide it across instances with headroom for admin and monitoring sessions, and cap each pool accordingly. A pooler in front of the database is the standard remedy: applications connect to the pooler, which multiplexes onto a smaller number of real database connections. It also makes the ceiling explicit rather than implicit.
Step 4 — check the network and the server’s health
If direct connections work and the pool has capacity, examine the path and the server. A firewall or security group may permit the port from one subnet and not another; a managed database may require an allow-listed address; a hostname may resolve to a private address that is unreachable from where the application runs. These produce a consistent timeout rather than an intermittent one, which is a useful signal.
Finally, consider whether the database is simply saturated. When it is out of memory or disk, or its CPU is pegged, accepting connections slows down and new ones time out while existing ones continue. That is a capacity problem whose symptom looks like a network problem. Check the database’s own metrics at the time of failure before concluding the path is at fault.
Where this bites vibecoders
AI-generated database code has two recurring flaws: it obtains a connection per request without a pooling layer, and it does not always release the connection on the error path. Under light load both are invisible. Under concurrency they exhaust the pool and produce exactly this timeout. Adding a pool is a configuration change; making every path release its connection is a code change, and it is the one that actually matters.
Where AI coding assistants get this wrong
- Opening a new database connection per request instead of using a pool.
- Failing to release a connection when a query throws, leaking a slot per error.
- Holding a connection open while doing slow work that is not a query.
- Raising the pool size without checking the database’s connection limit.
- Treating a connection timeout as if it were a slow query.
- Assuming a network problem without testing a direct connection first.
Checklist
- Confirm the error is on connect rather than on the statement.
- Test a direct connection from the application’s host.
- Check pool open, idle, and waiting counts during the failure.
- Verify every code path releases its connection, including error paths.
- Budget total connections across all instances against the database’s limit.
- Check firewall, security group, and hostname resolution for the database port.
FAQ
What is the difference between a connection timeout and a query timeout?
A connection timeout means the client could not establish a connection to the database at all, so the query never ran. A query timeout means the connection was established and the statement took too long. The first points at pooling, limits, or networking; the second points at query performance and indexes.
Why do I get connection timeouts only under load?
That is the signature of pool exhaustion. At low concurrency there are always free connections; at high concurrency requests queue for one and time out. Look at whether connections are being released on every path, and size the pool to the number of concurrent queries rather than the number of concurrent requests.
Should I just increase the pool size?
Not first. If connections are being leaked, a larger pool only delays the failure and consumes more of the database’s connection budget, which is shared with every other client. Fix the lifecycle, then size the pool against the actual concurrency, and consider a pooler if many instances need to share a limited connection budget.
How many connections should my pool use?
Enough for the number of genuinely simultaneous queries, not the number of requests, and few enough that all instances together stay under the database’s limit with headroom for admin and monitoring sessions. Start by measuring both the concurrency and the time each query holds a connection, then cap the pool and verify that waiting time stays near zero.
Related topics
- Connection Pool Exhausted: What It Is and How to Fix It
- What Is a Connection Pool?
- What Is a 504 Gateway Timeout (and How Do You Fix It)?
- How to Fix ‘Too Many Connections’ in Postgres
- Why Is My Website Suddenly Slow?
- What Is a Database Transaction (ACID)?