I just want to emphasize the most important line of the Heroku/Puma article that was referenced here:
Rails maintains its own database connection pool, with a new pool
created for each worker process. Threads within a worker will operate
on the same pool.
It states that each Worker will have its own Pool. However:
Threads within a worker will operate on the same pool.
This is very important to understand. If a Puma Worker utilizes 5 threads per worker, then the database.yml must be configured to a connection pool of 5, since each thread could possibly establish a database connection.
Since each Worker is spawned by a system fork(), the new worker will have its own set of 5 threads to work with, and thus for the new Rails instance created, the database.yml will still be set to a connection pool of 5.
Now the database.yml connection pool and your actual database pool are two different things. The TOTAL connections to your database will need to use a specific formula that the Heroku docs mention:
A good formula for determining the number of connections each application will require is to multiply the RAILS_MAX_THREADS by the WEB_CONCURRENCY.
What this means is if you are using 2 Workers, each with 5 threads, then 2 * 5 = 10, so your database must be configured to accept 10 concurrent connections.