Australian cloud for business software — built and run in Sydney since 2003

NetLeverage
NetLeverage

SQL Connection Pool Timeout: Find Leaked or Long-Held Connections

Technical article
Troubleshooting

A connection-pool timeout means the application could not obtain a usable connection within the allowed wait. It does not prove that SQL Server refused a login, and it does not prove a leak. Connections may be undisposed, held by slow work, reserved by transactions or divided among unexpectedly many pools.1

Start with the exact exception and the code operation that raised it. The durable correction follows the resource ownership and wait, rather than immediately increasing the pool limit.

This article covers Microsoft.Data.SqlClient. Record the actual package and runtime versions before applying provider-specific options; newer pool implementation switches are deliberately excluded.

Know which wait expired

An application can time out while opening a connection, while waiting for a pooled connection, or while executing a command. These occur at different boundaries. Preserve the full exception privately and provide a sanitised summary with the failing operation and elapsed time.

The provider documentation explains that when a pool has reached its maximum and no usable connection is available, subsequent opens wait for a connection to return. If that wait exceeds Connect Timeout, the open fails.1

That client-side wait can occur even while the server is reachable. A successful connectivity test from another process therefore does not disprove exhaustion in the application's pool.

Likewise, command duration may be the upstream reason connections remain occupied. A pool symptom and server blocking can be part of the same causal chain. The evidence should connect them without calling every timeout a network problem.

Pools belong to client configurations

Pooling is local to the application process. Each matching configuration has its own pool; application instances do not share one central pool merely because they connect to the same database.1

The provider uses exact connection-string matching. Differences in keyword order can create separate pools even when the effective settings are equivalent. Windows identity under integrated authentication and other authentication configuration can also affect pooling.1

This makes connection-string construction part of the investigation. Compare a sanitised configuration fingerprint, not raw strings containing passwords or tokens. Record the relevant settings and identity boundary while keeping credentials out of logs.

A hypothetical application that inserts a request identifier into its application-name setting can create high-cardinality configuration differences. The corrective question is whether that value belongs in connection configuration at all. Do not remove intentional database or identity isolation merely to reduce the number of pools.

Closing is a return, not necessarily a physical disconnect

When pooling is enabled, closing or disposing a logical connection normally returns its physical connection for reuse. The provider recommends opening late and disposing promptly, rather than keeping one connection globally open.1

This explains why an idle-looking SQL session can remain visible after application code closes a connection. Server session count alone cannot distinguish healthy pooled capacity from an application holding connections unnecessarily.

Trace ownership through success, exception, cancellation and early-return paths. Check readers and commands as well as connection objects. A resource that is disposed on the normal path but retained when parsing fails can produce intermittent exhaustion under bad input.

Avoid relying on eventual garbage collection to return scarce resources. The review should establish deterministic cleanup at the correct scope, including asynchronous paths. This article does not provide a code replacement without knowing the application's lifetime and transaction model.

Measure how long connections are held

Separate time waiting to obtain a connection from time holding one. Within the holding interval, distinguish database execution, result consumption, transaction work and unrelated application activity.

As a planning approximation under stable load, concurrent occupancy depends on how often connections are acquired and how long they remain occupied. This is an editorial capacity model, not a substitute for observed pool counters or a precise prediction during bursts.

If code acquires a connection and then waits on an unrelated external API before disposing it, the pool pays for the whole holding interval. If result processing is slow, the connection may remain occupied after the initial query has produced rows. Review the actual lifecycle rather than only the query's server execution time.

Correlate pool activity with server waits and blocking over the same interval. A slow or blocked database operation can make correctly disposed connections return too slowly for current demand. Fixing a disposal pattern will not resolve that separate bottleneck.

Transactions can keep capacity reserved

With default enlistment, a connection opened under an ambient transaction can join that transaction. The provider documents transaction-specific subdivisions: closing the logical connection does not necessarily return its physical connection to general use before the transaction completes.1

This is why a code review that finds a disposal statement may still miss the cause. Inspect transaction scope, duration and completion, including work performed outside the database while the transaction remains active.

Do not disable enlistment as a generic pool workaround. That changes transaction semantics and may break the atomicity the application requires. The right fix is to make the intended transaction boundary explicit and verify it.

Record stasis or transaction-related evidence where the installed provider exposes it. Keep metric names matched to that provider version rather than copying a counter list from a different package.

Distinguish fragmentation from saturation

Many pools with low individual utilisation suggest a different problem from one pool consistently at its limit. Collect active/free connection information, pool counts and physical-versus-logical connection activity using supported diagnostics.1

The current provider guide also describes authentication blocking periods, during which matching attempts can receive the original authentication exception without another login attempt. This mechanism depends on configuration and endpoint handling; it is not the same as waiting for a checked-out connection.1

The provider guide recommends leaving Pool Blocking Period at Auto unless there is a specific tested reason to override it. Disabling the blocking period can turn an authentication or outage problem into repeated login pressure.1

Preserve the first authentication error and retry timing if that pattern is suspected. Tight retry loops can obscure the original failure and increase pressure. Do not clear pools repeatedly as a substitute for understanding the exception.

Pool clearing causes later opens to establish physical connections again. It has legitimate uses at known configuration or credential boundaries, but the provider explicitly advises against using it as periodic maintenance or a disposal substitute.1

Size the solution across the whole application

Before raising Max Pool Size, account for every pool in every application process and instance. A local increase can multiply into much greater potential database concurrency. The database must be able to handle the resulting workload, not merely the number of logins.1

If measured demand is legitimate and connection lifetimes are appropriate, a capacity change may be justified. It should include database limits, application concurrency, retry behaviour and representative-load verification.

If ownership is defective, a larger pool may only delay exhaustion. If the database is blocked or saturated, extra concurrency may increase outstanding work. The diagnosis determines which intervention is appropriate.

Verify both resource return and user outcome

After an approved fix, compare pool waits, occupancy, acquisition and holding durations, request failures and database behaviour under comparable load. Exercise error and cancellation paths that previously retained resources.

A restart that clears the symptom is evidence that state was reset, not that ownership was corrected. The closure record should identify the specific lifetime or capacity cause and show that it no longer accumulates under the relevant scenario.

Learning notes

  • Pool acquisition, login and command timeouts require different evidence.
  • Disposal returns connections for reuse; server sessions may legitimately remain.
  • Long transactions and slow work can exhaust a pool without a simple leak.
  • Pool limits must be evaluated across all configurations and application instances.

Acceptance checklist

  • [ ] The exact exception distinguishes acquisition waits from login or command timeouts.
  • [ ] Pool identity, occupancy, holding duration and transaction reservations are evidenced.
  • [ ] Normal, error and cancellation paths return resources as intended.
  • [ ] Comparable load meets service limits without hiding pressure through repeated pool clears.

References

  1. SQL Server connection pooling with Microsoft.Data.SqlClient - ADO.NET Provider for SQL Server | Microsoft Learn. Accessed 2026-11-01.

Related articles