Repository navigation
SqlConnection.OpenAsync() may block on network i/o during connection creation #979
Description
Activity
Hi @coderb
Thanks for opening up this issue. This is a known design issue as driver internals are still synchronously designed and not everything supports awaiting yet. It's also a very heavy activity and requires major rework in the driver.
We'll have to see if this receives more community interest and shall be prioritized accordingly.
- addedPerformance 📈Issues that are targeted to performance improvements.Issues that are targeted to performance improvements.
on Mar 10, 2021 Would it be better to implement
OpenAsync()asreturn Task.Run(connection.Open)in the interim which would unblock the caller thread? This way users can code to the async api without workarounds and the application code wouldn't need to be updated when the library is fully async.Reacted by madelson and Arthur Vickers@coderb I'm personally not a fan of having async methods needlessly do that, since it just adds overhead for the common case. 100% agree that OpenAsync() should be implemented with as much asynchrony as possible, though.
We'll have to see if this receives more community interest and shall be prioritized accordingly.
@cheenamalhotra my worry is that this issue is going to be pretty invisible to most unless it causes a major problem. I certainly had assumed that
OpenAsync()was fully asynchronous at this point, but never thought to dig in and check.Reacted by Philippe VlérickWould it be better to implement OpenAsync() as return Task.Run(connection.Open) in the interim which would unblock the caller thread?
This could trigger TP starvation issues, as TP threads synchronously block on connection.Open, and so none are available to execute async callbacks.
Reacted by madelson, Arthur Vickers and John SchmeichelWe experienced a thread pool starvation issue today with this, while having connection pooling disabled.
28000 treads created for 28000 SQL calls in 12min30s. Hugues process pauses.
Reactivating SqlConnection pooling fixes the issue.1ms threads are created just to initiate the connection.
FYI, we disabled pooling because of a process needing to make a few calls on 2000 distinct databases, with specific connection string for each.
Reacted by Kyle WascherClosing the issue as it is by design. Feel free to comment here or open a new issue.
Reacted by madelson@JRahnama are you saying it's by-design for OpenAsync to perform synchronous I/O and block the thread? OpenAsync really should never block the thread on I/O.
Reacted by madelson and Thiago Oliveira SantosReacted by Kyle Wascher and Thiago Oliveira Santos@roji I mixed this issue with another one I was looking at. Thanks for catching my mistake.
Reopening the issue as it was closed by mistake.
Reacted by Shay Rojansky and Thiago Oliveira SantosCan we remove the "By Design" label, so this issue could get more attention?
Reacted by Javad Rahnama and madelsonI support this issue as it can remove a little bottleneck specially when we're talking about aspnet core. Due to the fact asptnet core controls multiple requests mainly through Tasks, not Threads, the fact OpenAsync actually runs syncrhonously under the hood makes requests on the same Thread to be queued until each one acquires a Connection from the pool.
Of course, if the connections are already created, this is not an issue at all, but let's suppose the minimum pool is 1, while the maximum is 100 (default config), the api is almost idle and a sudden heavy load reaches the API. In this scenario, multiple connection we'll be created, causing an undesired enqueing of OpenAsync calls on the Thread, even though SQL Server may easily handle multiple connections being stablished.
A similar issue may happen in any application focused on Tasks, like a custom one to consume a SQS Queue, for example.
Reacted by Raphael- added a parent issue
on Apr 1, 2026 - addedPerformance 📈Issues that are targeted to performance improvements.Issues that are targeted to performance improvements.and removedPerformance 📈Issues that are targeted to performance improvements.Issues that are targeted to performance improvements.
on Jun 10, 2026 - added a commit that references this issue
on Aug 24, 2026 /triage
🔍 Triage Summary (on-demand re-triage)
Check Result Issue type Bug Environment ⚠️ Missing: SQL Server version, Operating System (SqlClient version2.1.0and .NET targetnetcorewere provided in the original report; a full repro/stack trace and expected-vs-actual behavior were also provided)Area Area\Async(already applied)Duplicates Potentially related: #4696, #4534, #1562 (related async/deadlock/perf issues in the same OpenAsync code path); this issue is also tracked as a child of parent epic #3459 "[PLACEHOLDER] Improve Async Pathways in Connectivity APIs" Regression Not indicated — this is a long-standing design limitation, not a regression from a specific prior version Analysis
SqlConnection.OpenAsync()internally performs synchronous, blocking network I/O (viaTdsParser.Connect→SNIOpenSyncEx/native SNI) rather than fully awaiting, which can starve the thread pool and hang UI/async-heavy callers (e.g., ASP.NET Core under load, WinForms/WPF UI threads) when connections are created rather than reused from the pool. This is a well-known, long-discussed architectural issue (open since 2021, 11 comments, 9 👍 reactions) affectingArea\Asyncand connection establishment broadly. Severity: P2 (not a crash, but a real production reliability/perf issue under connection-pool churn or server failover); an earlier fix attempt (PR #2384) was opened but closed without merging.Next Steps
- Since this issue already has an attached (closed, unmerged) PR fix: Making open operation async first #2384 and is tracked under the broader epic Improve Async Pathways in Connectivity APIs #3459, recommend reviewing the epic and PR history before starting new work to avoid duplicating prior design discussion.
- Assign to Copilot coding agent to investigate reviving/adapting the approach from PR fix: Making open operation async first #2384 — making the internal
Open/login/SNI-connect path async-first (e.g.,TdsParser.Connect,SqlInternalConnectionTds.AttemptOneLogin, and native/managed SNI handle creation) soOpenAsync()truly awaits I/O instead of blocking, with the synchronousOpen()path implemented viaGetAwaiter().GetResult()on the same async core. - Consider cross-referencing Deadlock when a cancelled OpenAsync enlists in an ambient TransactionScope (Pooling=false) #4696, Sync ExecuteReader on an STA thread deadlocks against a StateChange handler that marshals to the UI thread (OpenAsyncRetry path) #4534, and Huge performance problem with async #1562 as they touch overlapping OpenAsync/async-deadlock code paths and may share a common root cause or fix surface.
- Missing environment fields (SQL Server version, OS) are non-blocking here since the issue is an accepted, well-understood design/architecture problem rather than an environment-specific repro — no label change needed for a
/triageon-demand run.
Note: This triage summary is auto-generated by an AI agent. The analysis and suggestions above have not been verified by a human maintainer. Please treat as preliminary guidance only.
Generated by SqlClient Issue Auto-Triage for #979 · copilot · auto · 55.1 AIC · ⌖ 13.1 AIC · ⊞ 11.9K · ◷
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsBacklog

please see the stack trace below.
SqlConnection.OpenAsync() has a code path that does synchronous blocking network i/o to the sql server.
my use case is a sql server reboot during a client request. the stack below was called from a u/i thread which subsequently hung the application due to OpenAsync() doing synchronous network i/o rather than awaiting.
(version 2.1.0 netcore)