Free tools Windows power users keep installed
One-click scans. No signup required.
First identify which pool is failing: Microsoft.Data.SqlClient’s database connection pool or System.Net.Http’s outbound HTTP connection pool. A SQL timeout while acquiring a connection and HTTP requests waiting for a connection are different problems, with different counters and fixes. Capture the exact exception and inspect the relevant pool during the incident before changing limits.
Identify the pool from the failure
Record the complete exception and stack trace, provider and package version, .NET runtime version, affected endpoint or dependency, and incident time. Note whether the symptom coincided with a traffic spike, deployment, database failover, or scale-out event.
For SQL Server using SqlClient, the characteristic error is: System.InvalidOperationException: Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached. Microsoft describes this in its SqlClient troubleshooting guide. It means the caller could not obtain a pooled connection before the timeout; it does not, by itself, explain why connections were unavailable.
HTTP symptoms may instead be described as socket exhaustion, no free connection, or requests waiting in a queue. Do not use SQL pool counters to diagnose HTTP queueing, or HTTP metrics to explain a SqlClient acquisition timeout.
#1 Best Overall
Diagnose Microsoft.Data.SqlClient pool pressure
Collect provider counters during the incident
For Microsoft.Data.SqlClient 3.0.0 and later on .NET Core 3.1 or later, or .NET Standard 2.1 or later, Microsoft documents EventCounters. A starting command is:
dotnet-counters monitor --counters Microsoft.Data.SqlClient.EventSource[hard-connects,hard-disconnects] -p <process-id>
Expand the requested counter list to include the relevant metrics supported by the deployed provider version, including number-of-active-connections, number-of-free-connections, number-of-active-connection-pools, number-of-active-connection-pool-groups, number-of-stasis-connections, and number-of-reclaimed-connections. Microsoft explains the available counters and collection in its Event counters in SqlClient documentation.
Hard connect and disconnect counters track actual opens and closes to the server; soft counters reflect checkout and return activity against the pool. A pattern of active connections approaching the configured pool ceiling while free connections are near zero during acquisition timeouts is consistent with saturation, not proof of a leak. Reclaimed connections—connection objects collected without explicit close or dispose—are a reason to inspect ownership and cleanup paths.
Rank #2
Counter collection differs by platform and framework: Microsoft documents EventCounters for modern .NET and Performance Counters for .NET Framework, with the latter being Windows- and .NET Framework-specific. Check names and availability against the exact runtime and provider version.
Correlate application metrics with SQL Server
Compare pool counters with SQL Server sessions, waits, blocking, query duration, and server capacity. Microsoft lists several possible explanations for unavailable pooled connections: connections not being closed or disposed promptly, slow queries, blocked transactions, excessive concurrency, pool fragmentation, or database capacity limits. Rising active pool or pool-group counts can point toward fragmentation by configuration or identity. The SQL Server connection pooling guidance describes these diagnostic signals and causes.
Inspect connection lifetime and work performed while checked out
- Ensure every opened
SqlConnectionis closed or disposed promptly, including on exceptional paths. In ordinary ADO.NET use, disposing returns a logical connection to the pool; it does not necessarily close the underlying physical database connection. - Look for code that holds a connection during unrelated remote calls, response streaming, lengthy CPU work, or user interaction.
- Keep transactions bounded, and verify that readers, commands, and transaction scopes complete as intended.
- Measure checkout duration before raising the pool maximum. Long holds reduce the number of connections immediately available to other requests.
These checks identify where to investigate; a high active count or reclaimed-connection signal alone does not establish that the application has a specific cleanup bug.
Check pool identity and application scale
SqlClient pools are local to an application process, so separate ASP.NET Core instances do not share a pool. Pool grouping depends on connection configuration; with integrated security, distinct Windows identities can create separate pools even when the connection string is otherwise identical. Inspect how connection strings and identities are constructed, and avoid unnecessary variations when connections are intended to share a pool.
Include every replica and process in the database connection budget. Scaling out can multiply the potential aggregate connections, so a per-process pool limit is not a safe estimate of the total database load.
Recommended Free Tools
Diagnose outbound HTTP connection pressure separately
Measure open connections and queue time
Microsoft’s System.Net metrics reference lists http.client.open_connections, http.client.active_requests, http.client.request.duration, and http.client.request.time_in_queue. The open-connections metric includes active and idle connections. Where instrumentation exposes destination and protocol attributes, group by them and compare queue delay and connection counts with request concurrency and downstream latency. See System.Net metrics for metric details and runtime availability.
These metrics are documented as available starting in .NET 8. The http.client.open_connections instrument is an UpDownCounter in .NET 8 through .NET 10 and an ObservableUpDownCounter starting in .NET 11. Verify that the runtime and instrumentation in use expose the signals you expect.
Separate queueing from connection setup
Microsoft describes the queue behavior directly: “When making a request, if there’s no connection immediately available in the connection pool, the request is added to a request queue to wait for an available connection.” A high http.client.request.time_in_queue points to waiting for a pooled connection; it is not the same as slow DNS, TCP, or TLS setup.
.NET 9 introduced experimental connection-setup tracing with DNS, TCP, and TLS phases. It can help distinguish time spent establishing connections from waiting for or using a pooled connection, but the feature is experimental; verify support in the runtime before relying on it. See Microsoft’s Networking tracing documentation.
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Fix the driver behind crashes, sound loss and screen glitches3Clear out junk files and repair common Windows errorsBest Value
- Applying all key ASP.NET Core components, including MVC for HTML generation, .NET Core, EF Core, ASP.NET Identity, dependency injection, and more
- Integrating ASP.NET Core with leading client-side frameworks, including Bootstrap
- ASP.NET Core code for implementing business logic and data transformations
- Handling configuration, routing, controllers, views, and common tasks (including posting forms and presenting data)
- Performing complementary tasks: error handling, logging, application design, authentication, localization, and more
Review client reuse, protocol, and concurrency
Each HttpClient instance has its own connection pool. Microsoft recommends reuse through a supported lifetime pattern, such as IHttpClientFactory or a long-lived client with an appropriately configured handler; the factory pools handlers. For a burst of concurrent HTTP/1.1 requests, consider a deliberate MaxConnectionsPerServer bound or HTTP/2 multiplexing, but measure latency and downstream capacity before changing concurrency. These controls concern outbound HTTP pools, not database connection exhaustion. See HttpClient guidelines for .NET and Use the IHttpClientFactory.
Fix the cause, then validate under load
For SQL pressure, address the evidence you found: prompt connection disposal, long checkout periods, slow queries or blocking, pool fragmentation, excessive concurrency, or server capacity. Microsoft lists increasing Max Pool Size as an option for the reported exhaustion error, but a higher cap can shift pressure to the database and may only postpone timeouts. Check the database’s ability to sustain added concurrency and account for aggregate connections across all instances before raising it.
For HTTP pressure, correct client or handler lifetime and tune per-server concurrency only after checking protocol, queue time, and downstream latency. Do not apply a SQL pool setting to an HTTP pool or vice versa.
After a change, compare the same signals under representative load: SQL acquisition latency, active and free connections, pool and group counts, hard and soft connect rates, database sessions and waits, HTTP open connections and queue time where applicable, error rate, and request latency. There is no universal correct pool size or concurrency limit; validate the result against the service’s workload and backend capacity.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

