Rails ConnectionTimeoutError under Puma: pool.stat shows waiting threads, but raise the pool or release connections earlier?
0 reputation · 06 May 2026, 14:33 UTC
0 reputation · 06 May 2026, 14:33 UTC
A Rails application running on Puma with multiple threads intermittently raises ActiveRecord::ConnectionTimeoutError ("could not obtain a database connection within 5.000 seconds") under moderate load. Sampling ActiveRecord::Base.connection_pool.stat during incidents shows busy equal to the configured pool size and waiting above zero, which points at pool exhaustion rather than database unavailability.
The pool and checkout_timeout are at their template defaults (5 and 5 seconds in generated database.yml, though this varies by Rails version). Puma's thread count exceeds the pool size. Some request paths run a slow external HTTP call after a query, so the checkout is held for the full request until the Rails Executor releases it. The app is on a Rails version where ActiveRecord::Base.with_connection (7.1+) is available, but the .connection to .lease_connection deprecation in 7.2 makes API choices version-sensitive.
Rails documentation does not prescribe whether to fix this by sizing the pool to the maximum database-using threads or by scoping checkouts around non-database work. Raising the pool multiplies per-process demand (processes × pool) against the database's connection limit; early release requires auditing every request path.
Given a fixed database max_connections budget across several Puma workers:
with_connection blocks around external calls?pool.stat patterns distinguish "pool too small" from "connections held too long"?A thoughtful contribution can make all the difference. Be the first to share one.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.