August 28th, 2026
like1 reaction

Try the new SqlClient and Retry connections natively

Principal Program Manager

The 2002 release of the original .NET Framework shipped ADO.NET and System.Data.SqlClient, the driver for SQL Server that gave .NET applications a standard connection approach. Over the years, updates, enhancements, and patches solidified these BCL classes as an integral dependency for millions of line-of-business applications that fueled innovation, business, and the world economy.

Then in 2019, 17 years later, Microsoft introduced Microsoft.Data.SqlClient, a new .NET driver for SQL Server that was better in almost every way. Side-stepping the calcification all software inherits over time, but maintaining Microsoft’s critical commitment to backward compatibility, it replaced System.Data.SqlClient with an elegant new code base offering new features, security, and capabilities for the modern data-driven application.

To migrate from System.Data.SqlClient

The Microsoft.Data.SqlClient namespace is essentially a new version of the System.Data.SqlClient namespace. Microsoft.Data.SqlClient generally maintains the same API and backward compatibility with System.Data.SqlClient. To migrate from System.Data.SqlClient to Microsoft.Data.SqlClient, for most applications, it’s simple. Add a NuGet dependency on Microsoft.Data.SqlClient and update references and using statements to Microsoft.Data.SqlClient.

Based on telemetry, a startling number of applications haven’t read the memo and updated. So, let me take a moment to talk about an incredible feature of SqlClient we previewed in 2021: Configurable Retry Logic for SqlConnection and SqlCommand. This native implementation of resiliency side-steps the need for third-party libraries like Polly, providing incredible handling of transient availability right out of the box.

Configurable Retry Logic

Since reaching General Availability in SqlClient 4.0, configurable retry logic in Microsoft.Data.SqlClient has provided a practical answer to a simple reality: sometimes, stuff happens. The best hardware, the best software, and the best networks still experience hiccups. A brief outage, a dropped connection, or even someone tripping over a power cable can make the best-designed architecture fail for just a second.

Retry logic is often the best answer for transient failures. It’s in the same category as closing and reopening the app, hitting refresh, or just turning something off and back on again. A simple retry is often all it takes to handle the intermittency of the real world. Its simplicity is its beauty; it doesn’t require additional bandwidth, redundancy, or a dead-letter queue. A well-defined retry policy can cover a myriad of troubles with just the right finesse.

Top features

Of course, every developer would expect to see the basics: fixed, incremental, and exponential retry intervals; configurable retry counts and delays; and support for both SqlConnection and SqlCommand. But SqlClient goes further with SQL-aware transient error detection, customizable transient error lists, command filtering, retry event notifications, and policies that can be configured in code or configuration. Because the retry happens inside the driver, it understands SQL Server in ways a general-purpose retry library simply cannot.

In its most basic usage, the syntax is simple:

var options = new SqlRetryLogicOption
{
    NumberOfTries = 5,
    DeltaTime = TimeSpan.FromSeconds(1),
    MaxTimeInterval = TimeSpan.FromSeconds(20)
};

var retryProvider =
    SqlConfigurableRetryFactory.CreateExponentialRetryProvider(options);

using var connection = new SqlConnection(connectionString)
{
    RetryLogicProvider = retryProvider
};

await connection.OpenAsync();

That’s it. If OpenAsync() encounters one of SqlClient’s recognized transient errors, it retries automatically using exponential backoff with built-in jitter. NumberOfTries = 5 means one initial attempt plus up to four retries. Also,  BaselineTransientErrors now exposes the built-in transient-error list, making it easier to extend SQL-aware retry behavior.

Retry is disabled by default; assigning a provider opts the connection or command into retry behavior.

Better than Polly?

Fundamentally, configurable retry in SqlClient solves the same retry problem as Polly, but there are key areas where being inside the SQL driver gives it an advantage. SqlClient already understands SQL Server transient errors, knows whether it is retrying a connection or command, avoids retrying commands inside active transactions, and exposes SQL-specific retry events and configuration.

Polly remains the better choice when

Polly remains the better choice when you need broader application resiliency like circuit breakers, fallbacks, hedging, or retry policies that span multiple dependencies. But for SQL retry alone, SqlClient is simpler, more focused, and more SQL-aware.

What’s more, SqlClient’s retry provider is reusable. Define the policy once, then assign it directly to SqlConnection or SqlCommand without wrapping every database call in a separate resilience pipeline. The retry stays close to the failure, where the driver has the most context to decide what should happen next.

Getting Started

Start with an upgrade. If you are still using System.Data.SqlClient then its time to upgrade to Microsoft.Data.SqlClient and take advantage of decades of improvements and scores of enhancements like configurable retry. Now in version 7.x, Microsoft.Data.SqlClient is typically a drop-in replacement. In some cases, it can take a little well-deserved refactoring to get going, especially if new features are your motivation.

Author

Jerry Nixon
Principal Program Manager

SQL Server Developer Experience Program Manager for Data API builder.

0 comments