✨ Strapi MCP is now Generally Available - let your agents manage your Strapi content ✨

EcosystemAdvanced5 min read

What "Knex: Timeout acquiring a connection. The pool is probably full." really means in Strapi

September 8, 2026
What "Knex: Timeout acquiring a connection. The pool is probably full." really means in Strapi

Your Strapi app starts, hangs for a minute, then dies with:

Knex: Timeout acquiring a connection. The pool is probably full.
Are you missing a .transacting(trx) call?

This message is one of the least helpful errors in the Node ecosystem. It is generated by Knex, Strapi's query builder, and it fires whenever Knex waits longer than acquireConnectionTimeout for a usable connection. The message then guesses at a cause, a full pool or a missing transaction, and that guess is usually wrong.

In the overwhelming majority of Strapi cases, the pool is not full. Strapi cannot reach the database at all.

Knex asks the pool for a connection, the pool tries to create one, the TCP connection hangs because a firewall is dropping the packets, and 60 seconds later Knex reports the only thing it knows: it never got a connection.

Triage in the right order

1. Can anything reach the database from where Strapi runs?

Do this before touching a single config value. From the same machine, container, or dyno that runs Strapi:

# Is the port even open?
nc -zv your-db-host.example.com 5432

# PostgreSQL
psql "postgresql://USER:PASSWORD@your-db-host.example.com:5432/DBNAME" -c "select 1;"

# MySQL / MariaDB
mysql -h your-db-host.example.com -P 3306 -u USER -p -e "select 1;"

If nc hangs, this is a network problem and no pool setting will fix it. The usual culprits:

  • Your IP is not allowlisted. Managed Postgres on AWS RDS, Azure, Supabase, Neon, and DigitalOcean all default to denying inbound connections. This is the single most common cause, and it is what resolved the original forum thread: the poster's home IP had changed and was no longer in the allowlist.
  • The security group or firewall rule targets the wrong source. An RDS security group that allows your laptop will not allow your ECS task.
  • The database is in a private subnet and Strapi is not.
  • A Docker network mismatch. Inside Compose, localhost means the Strapi container, not the database container. Use the service name (postgres, db) as the host.

2. Read the database's own log

The database log tells you what Strapi's log cannot. Look for rejected connections, authentication failures, and "too many connections" errors. A refused connection that never reaches the server leaves no trace there at all, which is itself a useful signal that the problem is upstream in the network.

3. Check whether you have actually exhausted connections

If the network is fine and the database is reachable, then look at connection counts:

-- PostgreSQL
SELECT count(*), state FROM pg_stat_activity
WHERE datname = 'your_db' GROUP BY state;

SHOW max_connections;

Small managed instances are stingy. A Supabase free-tier pooler or an RDS db.t3.micro may cap you well below what several Strapi replicas plus your migrations plus your local psql session are trying to open at once.

Now the configuration

Strapi's pool options live under connection.pool in config/database, and are passed straight to Tarn.js via Knex. The defaults:

OptionDefault
min2
max10
acquireTimeoutMillis60000
createTimeoutMillis30000
idleTimeoutMillis30000
acquireConnectionTimeout (on connection, not pool)60000
export default ({ env }) => ({
  connection: {
    client: 'postgres',
    connection: {
      host: env('DATABASE_HOST', '127.0.0.1'),
      port: env.int('DATABASE_PORT', 5432),
      database: env('DATABASE_NAME', 'strapi'),
      user: env('DATABASE_USERNAME', 'strapi'),
      password: env('DATABASE_PASSWORD', 'strapi'),
      ssl: env.bool('DATABASE_SSL', false),
    },
    pool: {
      min: env.int('DATABASE_POOL_MIN', 2),
      max: env.int('DATABASE_POOL_MAX', 10),
    },
    acquireConnectionTimeout: env.int('DATABASE_CONNECTION_TIMEOUT', 60000),
  },
});

Two adjustments are genuinely worth making.

Running in Docker or on a serverless platform: set min: 0. The Strapi docs call this out explicitly. Docker and most serverless runtimes kill idle TCP connections. If the pool insists on keeping two connections alive, it hands out dead sockets and you get intermittent timeouts under low traffic, the confusing kind that only appear after the app has been quiet for a few minutes.

pool: { min: 0, max: 10 },

Running several replicas: divide max by the replica count. Four Strapi instances at max: 10 will try to open 40 connections. If the database allows 20, some of them will always be waiting.

What not to do

Forum threads on this error converge on a config block with every timeout cranked to five or six figures:

// Don't cargo-cult this
acquireConnectionTimeout: 1000000,
pool: {
  min: 0, max: 1,
  acquireTimeoutMillis: 300000,
  createTimeoutMillis: 300000,
  destroyTimeoutMillis: 300000,
},

This does not fix anything. It makes a broken deploy hang for five minutes instead of one before failing, and max: 1 serialises every query in your application. If raising a timeout appears to help, what you have actually found is a slow connection handshake, usually TLS negotiation against a distant database, and the fix is to move the database closer or fix the TLS config, not to wait longer.

Special cases worth knowing

Connection poolers. Supabase, PgBouncer, and RDS Proxy sit in front of Postgres in transaction-pooling mode. Point Strapi at the pooler's port (6543 on Supabase, not 5432), keep Strapi's own max low, and be aware that prepared statements and session-level features behave differently through a transaction pooler.

SSL. A database that requires SSL will hang or reject if Strapi connects without it. Set ssl: true, and for providers with self-signed certificates:

ssl: env.bool('DATABASE_SSL', false) && {
  rejectUnauthorized: env.bool('DATABASE_SSL_SELF', false),
},

Long-running custom queries. If you have written a controller that iterates records and issues a query per record without releasing connections, you can genuinely exhaust the pool. This is the case the error message was written for, and it is the rarest one. Look for strapi.db.connection usage in your own code and wrap multi-step work in a transaction.

The 30-second version

  1. nc -zv <db-host> <port> from the machine running Strapi. If it hangs, fix networking, not config.
  2. Check the allowlist / security group. Your IP probably changed.
  3. Read the database log.
  4. In Docker or serverless, set pool.min: 0.
  5. Only tune pool.max once you have confirmed the connection count is actually the limit.

Further reading

Theodore Kelechukwu OnyejiakuDevRel and Community | Software Developer | Technical Writer

Theodore is a Technical Writer and a full-stack software developer. He loves writing technical articles, building solutions, and sharing his expertise.

"Strapi is in production mode" when you are running development mode
EcosystemBeginner·5 min read

"Strapi is in production mode" When you are Running Development Mode

The Content-Type Builder is disabled and Strapi claims production, but your terminal says development. The rule Strapi actually applies, and the fix.

·September 9, 2026
Running Strapi in production with PM2
EcosystemIntermediate·6 min read

Running Strapi in production with PM2

Keep Strapi running across crashes and reboots with PM2: server.js, ecosystem files, TypeScript projects, log rotation, and the cluster-mode caveat.

·September 9, 2026
Why your Strapi API returns 403 Forbidden (and how to fix it)
EcosystemBeginner·6 min read

Why your Strapi API returns 403 Forbidden (and how to fix it)

A 403 from the Strapi REST API means authorisation, not authentication. The Public role, API tokens, Draft & Publish, and the cases in between.

·September 9, 2026