"Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool" is one of those errors that gets blamed on "the database being slow" when the actual cause is almost always upstream of SQL Server entirely: the app tier asked for more concurrent connections than the pool was configured to hand out, and everyone waited in line.
Where the pool is actually configured
Acumatica's connection strings live in web.config (or, on newer builds, the site's connection configuration in the Database Configuration Wizard output), and pooling parameters ride on the connection string itself as standard ADO.NET/SQL Server connection string keywords:
<add name="AcumaticaDB"
connectionString="Data Source=SQLPROD\ACU;Initial Catalog=AcumaticaProd;
Integrated Security=False;User ID=acu_app;Password=***;
Pooling=True;Min Pool Size=10;Max Pool Size=200;
Connect Timeout=30;Connection Lifetime=0"
providerName="System.Data.SqlClient" />
Max Pool Size is the number that actually matters under load — the default of 100 is frequently too low for a busy multi-user instance with several worker processes, because each app pool process gets its own pool. Three worker processes at the default cap out at 300 total connections to SQL Server combined, which needs to be checked against SQL Server's own max server memory and connection limits, not just bumped blindly.
Confirming it is pool exhaustion, not a slow query
Windows Performance Monitor exposes .NET Data Provider for SqlServer\NumberOfPooledConnections and NumberOfActiveConnections per process. If active connections sit flat at your configured max while requests queue, you are pool-bound. If active connections stay well under the max but requests are still slow, the pool is not your problem — go look at query execution time instead.
SELECT login_name, COUNT(*) AS open_connections
FROM sys.dm_exec_sessions
WHERE program_name LIKE '%Acumatica%' OR login_name = 'acu_app'
GROUP BY login_name
ORDER BY open_connections DESC;
What actually exhausts a pool in practice
- Long-running reports or GIs holding connections open for the duration of a slow query, starving short interactive requests of a connection to check out.
- Custom integration code that opens raw
SqlConnectionobjects outside the framework's data access layer and does not reliably close them in afinallyorusingblock — a leaked connection from a failed integration call is worse than a slow query, because it never comes back to the pool at all. - PXLongOperation-backed processing screens run at high concurrency — each concurrently processing user/batch can hold a connection for the operation's duration; a mass processing run during business hours competes with everyone else's interactive connections.
Doubling Max Pool Size makes the timeout go away for a while and pushes the real cost onto SQL Server, which now has to context-switch and manage locks across more concurrent sessions. If you are raising the pool size past a few hundred per app server to make timeouts stop, you have an underlying long-running-query or connection-leak problem that the bigger pool is hiding, not fixing. Fix the leak or the slow query first; resize the pool as capacity planning after that, not instead of it.
What I actually set, and why
Starting point for a mid-size production instance (a few dozen concurrent users, 2-3 app servers): Max Pool Size=200, Min Pool Size=10 (keeps a warm floor so the first requests after an app pool recycle are not all paying connection-open latency), Connection Lifetime=0 (let the pool manage recycling rather than forcing periodic resets, which is mostly relevant behind older load balancers that dislike long-lived TCP sessions). Adjust up only after confirming via Perfmon that you are actually pool-bound, not query-bound.
Wrapping up
A pool exhaustion timeout is an app-tier symptom with two possible app-tier causes — genuinely high concurrency, or a leak/long-holder eating connections that should have been returned — and resizing the pool only addresses the first. Measure active versus max pooled connections before touching the config, and audit custom integration code for connections that never get released.
Independent software engineer in Nairobi specialising in Acumatica customisations, Laravel backends, and tax fiscalisation integrations across East and Southern Africa.