{"id":7772,"date":"2026-10-06T15:42:12","date_gmt":"2026-10-06T22:42:12","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/azure-sql\/?p=7772"},"modified":"2026-10-06T15:44:09","modified_gmt":"2026-10-06T22:44:09","slug":"try-sqlclients-new-connection-pool-for-faster-parallel-connections","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/azure-sql\/try-sqlclients-new-connection-pool-for-faster-parallel-connections\/","title":{"rendered":"Try SqlClient\u2019s new connection pool for faster parallel connections"},"content":{"rendered":"<p style=\"font-weight: 400\">You told us that applications using <code>Microsoft.Data.SqlClient<\/code> can take too long to establish the database connections they need. When many requests need connections at the same time, waiting for the connection pool to grow can delay application readiness and increase latency. This can happen even in common situations like querying several pieces of metadata during startup or receiving a burst of traffic after a quiet period. <code>Microsoft.Data.SqlClient<\/code>\u2019s new connection pool (Pool V2) is designed to address this problem by establishing new connections concurrently, allowing the pool to respond more quickly when multiple requests need new connections at the same time.<\/p>\n<p style=\"font-weight: 400\">With the legacy connection pool, only one new connection can be opened at a time within a pool. Applications used to work around this limitation in creative ways, such as reserving capacity in advance by increasing <code>Min Pool Size<\/code> or disabling pooling altogether. These workarounds can now be entirely avoided.<\/p>\n<p style=\"font-weight: 400\">Pool V2 is also designed with asynchronous workloads in mind. Its core design uses <a href=\"https:\/\/learn.microsoft.com\/en-us\/dotnet\/api\/system.threading.channels\">System.Threading.Channels<\/a> \u2014 a set of producer-consumer data structures with first-class asynchronous support \u2014 rather than relying on dedicated background threads. This can reduce thread management overhead for applications that connect to many different databases. Thanks to the Npgsql driver team, who paved the way for this pooling design.<\/p>\n<h2>How does it perform?<\/h2>\n<p style=\"font-weight: 400\">We measured how quickly the legacy pool and Pool V2 could establish a set of connections during a cold start. Each test cleared the pool and then timed multiple concurrent callers opening and holding the same number of connections until all opens completed.<\/p>\n<p style=\"font-weight: 400\">The measured time includes connection creation, synchronization, and returning connections to the pool. Pool clearing and test setup are excluded. The results represent the mean time for the complete operation, not the latency of an individual connection open. Lower times are better.<\/p>\n<p style=\"font-weight: 400\">The tests used 10, 25, 50, and 100 concurrent callers with <code>Max Pool Size=200<\/code>. SQL Server ran on the same machine as the benchmark to reduce network variability. These benchmarks measure cold-start connection establishment and coordination. They do not measure SQL query execution or the reuse of connections in an already-warm pool. Results will vary based on workload and network latency.<\/p>\n<h3>Synchronous cold-start results<\/h3>\n<p style=\"font-weight: 400\">With 100 concurrent callers on Linux, Pool V2 reduced mean cold-start benchmark time from 630.1 ms to 117.5 ms, a 5.4x speedup.<\/p>\n<p style=\"font-weight: 400\">Synchronous callers use dedicated threads with <code>SqlConnection.Open()<\/code>. Each caller holds its connection until all opens complete. Lower times are better.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2026\/10\/01-cold-start-sync.svg\"><img decoding=\"async\" class=\"alignnone wp-image-7784 size-large\" role=\"img\" src=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2026\/10\/01-cold-start-sync.svg\" alt=\"A graph showing improved cold start times on linux and windows.\" width=\"1024\" height=\"1024\" \/><\/a><\/p>\n<h3>Asynchronous cold-start results<\/h3>\n<p style=\"font-weight: 400\">With 100 concurrent callers on Linux, Pool V2 reduced mean cold-start benchmark time from 604.1 ms to 92.0 ms, a 6.6x speedup.<\/p>\n<p style=\"font-weight: 400\">Asynchronous callers use tasks with <code>SqlConnection.OpenAsync()<\/code>. Each caller holds its connection until all opens complete. Lower times are better.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2026\/10\/02-cold-start-async.svg\"><img decoding=\"async\" class=\"alignnone wp-image-7785 size-large\" role=\"img\" src=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2026\/10\/02-cold-start-async.svg\" alt=\"A graph showing improved cold start times on linux and windows.\" width=\"1024\" height=\"1024\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<h3>Test environment<\/h3>\n<p style=\"font-weight: 400\">Linux: Ubuntu 22.04.5 LTS on a 16-core, 32-logical-CPU Intel Xeon Platinum 8168 VM, running SQL Server 2022 Developer CU26, .NET 9.0.19, and BenchmarkDotNet 0.15.8.<\/p>\n<p style=\"font-weight: 400\">Windows: Windows Server 2022 Datacenter Azure Edition on a 16-core, 32-logical-CPU Intel Xeon Platinum 8168 VM, running SQL Server 2025 Enterprise Evaluation RTM, .NET 9.0.19, and BenchmarkDotNet 0.15.8.<\/p>\n<p style=\"font-weight: 400\">The full benchmark source code is available in the <a href=\"https:\/\/github.com\/dotnet\/SqlClient\">dotnet\/SqlClient GitHub repository<\/a>.<\/p>\n<h3>Current asynchronous I\/O limitation<\/h3>\n<p style=\"font-weight: 400\"><code>SqlConnection.OpenAsync()<\/code> is not yet fully asynchronous down to each individual network call. Pool V2 currently queues work items on managed thread-pool threads that perform synchronous network calls. If those network calls experience high latency, the managed thread pool may experience elevated pressure. Waiting for additional threads to spin up can introduce end-user latency.<\/p>\n<p style=\"font-weight: 400\">Applications with high latency to SQL Server should monitor managed thread-pool pressure. If necessary, consider increasing the managed thread-pool size or enforcing a concurrency limit on database operations. Future work will correct these network calls to eliminate the extra managed thread pool pressure.<\/p>\n<h2>Try Pool V2 today<\/h2>\n<p style=\"font-weight: 400\">Pool V2 is available starting with <code>Microsoft.Data.SqlClient<\/code> 7.1.0. Enable it once during application startup, before any database connections are opened:<\/p>\n<pre class=\"prettyprint language-cs language-csharp\"><code class=\"language-cs language-csharp\">AppContext.SetSwitch(\r\n    \"Switch.Microsoft.Data.SqlClient.UseConnectionPoolV2\", \r\n    true);<\/code><\/pre>\n<p style=\"font-weight: 400\">Place the switch at the beginning of your application\u2019s entry point, before initializing services that might access the database. In an ASP.NET Core application, place it before creating the application builder.<\/p>\n<p style=\"font-weight: 400\">That is the only code change required. Your existing connection strings and database-access code remain unchanged. Pool V2 also works with EF Core, Dapper, and other libraries that use <code>Microsoft.Data.SqlClient<\/code>.<\/p>\n<p style=\"font-weight: 400\">Evaluate Pool V2 with a representative workload, particularly during:<\/p>\n<ul>\n<li style=\"font-weight: 400\">Application startup<\/li>\n<li style=\"font-weight: 400\">Traffic bursts after a quiet period<\/li>\n<li style=\"font-weight: 400\">High concurrent demand for database connections<\/li>\n<li style=\"font-weight: 400\">Higher-latency connections to SQL Server<\/li>\n<\/ul>\n<p style=\"font-weight: 400\">To switch back, set the switch to <code>false<\/code> and restart the application.<\/p>\n<p style=\"font-weight: 400\">We plan to make Pool V2 the default in a future <code>Microsoft.Data.SqlClient<\/code>\u00a0version, and your experience can provide helpful feedback. Share your results through <a href=\"https:\/\/github.com\/dotnet\/SqlClient\/issues\">dotnet\/SqlClient GitHub Issues<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>You told us that applications using Microsoft.Data.SqlClient can take too long to establish the database connections they need. When many requests need connections at the same time, waiting for the connection pool to grow can delay application readiness and increase latency. This can happen even in common situations like querying several pieces of metadata during [&hellip;]<\/p>\n","protected":false},"author":220461,"featured_media":7773,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[444,1,690],"tags":[],"class_list":["post-7772","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-net","category-azure-sql","category-drivers"],"acf":[],"blog_post_summary":"<p>You told us that applications using Microsoft.Data.SqlClient can take too long to establish the database connections they need. When many requests need connections at the same time, waiting for the connection pool to grow can delay application readiness and increase latency. This can happen even in common situations like querying several pieces of metadata during [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/posts\/7772","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/users\/220461"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/comments?post=7772"}],"version-history":[{"count":2,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/posts\/7772\/revisions"}],"predecessor-version":[{"id":7798,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/posts\/7772\/revisions\/7798"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/media\/7773"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/media?parent=7772"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/categories?post=7772"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/tags?post=7772"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}