Skip to content

Laravel error

Laravel: SQLSTATE[HY000] [1040] Too many connections

The error

SQLSTATE[HY000] [1040] Too many connections

The database refused a new connection because its limit is reached. The cause is almost never traffic - it is workers, long-running processes or a pool that nobody counted.

The error

Illuminate\Database\QueryException

SQLSTATE[HY000] [1040] Too many connections

Postgres words it as FATAL: sorry, too many clients already. Same situation.

What it means

The database has a maximum number of simultaneous connections and it is reached. The next process that tries to connect is refused - which in a web application means requests failing while the database itself is healthy and barely working.

The instinct is to look at traffic. Traffic is rarely the answer, because a web request connects, works and disconnects within milliseconds. What fills a connection limit is processes that connect and stay connected.

Count before changing anything

SHOW STATUS LIKE 'Threads_connected';
SHOW VARIABLES LIKE 'max_connections';
SELECT user, host, command, time, state FROM information_schema.processlist
ORDER BY time DESC;

That last query is the one that answers it. Connections sitting in Sleep with a large time are processes holding a connection they are not using - which is the shape of this problem almost every time.

The usual causes

Queue workers. Each one connects at boot and holds it. Twenty workers are twenty permanent connections before a single request arrives. Scaling workers to clear a backlog is the single most common way to arrive here, and the connection cost is invisible at the moment you do it.

Scheduled commands that overlap. A long-running command started every minute, taking three minutes, accumulates. withoutOverlapping() on the schedule costs nothing and prevents it.

Long-running processes generally. Octane workers, websocket servers, any daemon. Each holds a connection for its life.

Connections opened and not closed in a loop. Reconnecting inside an iteration, or a job that opens a second connection to another database per record.

A pooler configured larger than the database. Where one exists, its maximum has to be smaller than the database's, not larger. Two poolers each configured to the database's limit is a limit doubled.

The arithmetic nobody does

Work out the steady-state count before choosing a number:

(web servers × PHP-FPM max_children)
  + (queue workers)
  + (scheduler, at its worst overlap)
  + (long-running processes)
  + headroom for a deploy running two sets at once
  + a few for humans and monitoring

Most applications that hit this find the total is well over the limit and always was - it simply had never all been busy at once until the day it was.

Fixes that are not "raise the limit"

Fewer workers, each doing more. Ten workers processing quickly beat thirty waiting on the same database. Queue depth is the measure, not worker count.

Stop overlapping schedules.

Schedule::command('reports:build')->everyMinute()->withoutOverlapping();

Close what you open. A job that connects to a secondary database should disconnect when it is done rather than relying on the worker exiting.

Separate reads. A read replica for reporting moves the heaviest, longest connections off the primary, which also removes them from its limit.

Give the deploy room. Either stop old workers before starting new ones, or keep enough headroom that a brief overlap fits.

Then raise it, if the count justifies it

Each connection costs memory on the database server, and a limit set beyond what the machine can hold converts a clear error into swapping and timeouts. Raise it when the steady-state count is legitimate and the server has the memory - and write down what the number was based on, because the next person to scale workers needs to know a budget exists.

If the count is legitimate and the database is the constraint, a pooler in front of it usually beats a larger limit. On managed or serverless Postgres there is one already, and the mode it runs in decides what breaks. Choosing between more headroom and fewer connections is something we measure.

Related questions

Should we just raise max_connections?
Only after counting what is actually connecting, because each connection costs memory on the database server and a limit raised past what the machine can hold turns a refused connection into swapping, which is worse. Raise it when the count is legitimate and the machine can take it - not as the first move.
Do queue workers hold a connection permanently?
Effectively yes. A worker connects when it boots and keeps that connection for its life, whether or not it is processing anything. Thirty idle workers are thirty connections, which is why scaling workers is the most common cause of this error.
Does Octane make this worse?
It changes the arithmetic. Long-lived application workers hold connections the same way queue workers do, so the count becomes a function of your worker count rather than of concurrent requests. That is often fewer connections overall, and it is a number to work out rather than assume.
We see it only during deploys.
Then you are briefly running two sets of processes - the old ones finishing and the new ones starting - and the total exceeds the limit for a few seconds. Either the limit is too close to the steady-state count, or the deploy should stop the old workers before starting the new ones.
Call us+1 848 272 7583WhatsApp+90 850 308 5436Emailinfo@codefacture.comContact page