Fix Knex Connection Pool β Pool Exhaustion or Timeout
DodaTech
Updated 2026-06-24
3 min read
In this tutorial, you'll learn about Fix Knex Connection Pool. We cover key concepts, practical examples, and best practices.
Your application runs fine for a while, then queries start failing with "Timeout: acquiring a connection" or "Connection pool error: Pool is full". Restarting the app fixes it temporarily, but the issue returns under load.
Wrong β
// knexfile.js
module.exports = {
client: 'postgresql',
connection: {
host: 'localhost',
database: 'mydb',
user: 'postgres',
password: 'password',
},
// β No pool configuration β uses defaults (min: 2, max: 10)
};
Under 50 concurrent requests:
Error: Knex: Timeout acquiring a connection. The pool is full.
Knex's default pool (`min: 2, max: 10`) is exhausted. Connections are acquired but never released back to the pool.
## Right β
```<a href="/programming-languages/javascript/">javascript</a>
// knexfile.js
module.exports = {
client: '<a href="/databases/postgresql/">postgresql</a>',
connection: {
host: 'localhost',
database: 'mydb',
user: 'postgres',
password: 'password',
application_name: 'myapp', // identify in pg_stat_activity
},
pool: {
min: 2,
max: 20, // increased for concurrency
idleTimeoutMillis: 30000, // 30s idle β release
acquireTimeoutMillis: 10000, // wait 10s for a connection
createTimeoutMillis: 5000, // wait 5s to create a connection
createRetryIntervalMillis: 200, // retry every 200ms
propagateCreateError: false, // don't crash on first error
},
acquireConnectionTimeout: 15000, // overall timeout
};
**Debug connection leaks:**
```javascript
const knex = require('knex')(config);
// Before each query, log the pool state
console.log({
used: knex.client.pool.numUsed(), // connections in use
free: knex.client.pool.numFree(), // idle connections
pending: knex.client.pool.numPending(), // waiting to be created
});
// Or use the pool's event emitter (tarn.js)
knex.client.pool.on('pool:acquire', (resource) => {
console.log('Acquired connection:', resource.__knexUid);
});
knex.client.pool.on('pool:release', (resource) => {
console.log('Released connection:', resource.__knexUid);
});
**Always release connections:**
```<a href="/programming-languages/javascript/">javascript</a>
// β Wrong β never released
app.get('/users', async (req, res) => {
const users = await knex('users').select('*');
res.json(users);
// The connection is released automatically when the query completes
// BUT if you use knex.client.acquireConnection(), you must release it:
});
// β
Correct β raw connection management
app.get('/users', async (req, res) => {
const conn = await knex.client.acquireConnection();
try {
const result = await conn.query('SELECT * FROM users');
res.json(result.rows);
} finally {
knex.client.releaseConnection(conn); // must release
}
});
**Monitor connections in <a href="/databases/postgresql/">PostgreSQL</a>:**
```sql
SELECT state, count(*)
FROM pg_stat_activity
WHERE application_name = 'myapp'
GROUP BY state;
**Set up a pool eviction check:**
```<a href="/programming-languages/javascript/">javascript</a>
pool: {
min: 2,
max: 20,
idleTimeoutMillis: 30000,
reapIntervalMillis: 1000, // check for idle connections every 1s
log: (msg, level) => console.log(`[pool] ${level}: ${msg}`),
},
## Root Cause
Knex creates a connection pool using `tarn.js`. Under high concurrency, if connections aren't released (or the pool is too small), all connections are busy, and new queries wait for `acquireTimeoutMillis` before timing out.
## Prevention
- Match pool size to application concurrency and database limits.
- Always use `knex()` directly (not raw `acquireConnection`) β Knex autoβreleases.
- Monitor `pg_stat_activity` for connection leaks.
- Set `application_name` to identify your app's connections.
## Common Mistakes with connection pool
1. **Mixing let bindings with <- bindings in do notation, producing type errors**
2. **Overlapping type class instances that cause GHC to reject the program with ambiguous dispatch errors**
3. **Non-exhaustive pattern matches that compile with warnings then crash at runtime**
These mistakes appear frequently in real-world KNEX code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.
## Practice Exercise
**Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.**
This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.
## FAQ
<details style="margin-bottom:12px;border:1px solid #e2e8f0;border-radius:10px;overflow:hidden"><summary style="cursor:pointer;padding:14px 18px;font-weight:600;font-size:1.05rem;background:#f8fafc;border-bottom:1px solid #e2e8f0;color:#1e293b">**Q: What's the ideal pool size?**</summary><div style="padding:14px 18px;color:#475569;line-height:1.7;background:#fff"><p>A: Start with <code>max: 20</code> and adjust based on <code>max_connections</code> on the database and concurrent request volume.</p>
</div></details><details style="margin-bottom:12px;border:1px solid #e2e8f0;border-radius:10px;overflow:hidden"><summary style="cursor:pointer;padding:14px 18px;font-weight:600;font-size:1.05rem;background:#f8fafc;border-bottom:1px solid #e2e8f0;color:#1e293b">**Q: Can I use a different pool implementation?**</summary><div style="padding:14px 18px;color:#475569;line-height:1.7;background:#fff"><p>A: Knex uses <code>tarn.js</code> (builtβin). No alternative pool providers.</p>
</div></details><details style="margin-bottom:12px;border:1px solid #e2e8f0;border-radius:10px;overflow:hidden"><summary style="cursor:pointer;padding:14px 18px;font-weight:600;font-size:1.05rem;background:#f8fafc;border-bottom:1px solid #e2e8f0;color:#1e293b">**Q: How do I handle a database restart without crashing the app?**</summary><div style="padding:14px 18px;color:#475569;line-height:1.7;background:#fff"><p>A: Set <code>pool.createRetryIntervalMillis</code> and <code>pool.propagateCreateError: false</code>.</p>
</div></details><details style="margin-bottom:12px;border:1px solid #e2e8f0;border-radius:10px;overflow:hidden"><summary style="cursor:pointer;padding:14px 18px;font-weight:600;font-size:1.05rem;background:#f8fafc;border-bottom:1px solid #e2e8f0;color:#1e293b">**Q: Why does my pool have idle connections above `min`?**</summary><div style="padding:14px 18px;color:#475569;line-height:1.7;background:#fff"><p>A: Knex keeps connections alive for <code>idleTimeoutMillis</code> before destroying them.</p>
</div></details>
---
*Connection pooling is covered in the [DodaTech Knex.js Performance course](https://dodatech.com/courses/knex).*
β Previous
Kibana Visualization Not Loading Fix
Next β
Fix Knex Migrate Latest β Migration Not Applying
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro