Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Microsoft.Data.SqlClient is the supported provider for new SQL Server features in .NET applications. It preserves the ADO.NET programming model used by System.Data.SqlClient, but the packages, namespaces, defaults, and some public types differ.
Treat the migration as a provider update, not only a namespace replacement.
Plan the migration
Before changing code:
Record the versions of .NET,
System.Data.SqlClient, SQL Server, and Microsoft SQL services that the application supports.Inventory authentication modes, connection string keywords, custom certificates, Always Encrypted providers,
DbProviderFactoriesconfiguration, SQL Server user-defined types, andSystem.Data.SqlTypesusage.Run the application's current tests and save a baseline for connection, query, transaction, retry, and performance behavior.
Search direct and transitive package references:
dotnet list package --include-transitive
Migrate one application or shared data access library at a time. Don't pass provider-specific objects between code that still uses System.Data.SqlClient and code that uses Microsoft.Data.SqlClient.
Replace the package
Remove an explicit System.Data.SqlClient package reference, if present:
dotnet remove package System.Data.SqlClient
Add Microsoft.Data.SqlClient:
dotnet add package Microsoft.Data.SqlClient
If Microsoft.Data.SqlClient 7.0 or later uses a driver-provided Microsoft Entra authentication mode, also add:
dotnet add package Microsoft.Data.SqlClient.Extensions.Azure --version <same-version-as-Microsoft.Data.SqlClient>
For version and package selection, see Install, update, and deploy Microsoft.Data.SqlClient.
Update namespaces
Replace the primary provider namespace:
-using System.Data.SqlClient;
+using Microsoft.Data.SqlClient;
Update fully qualified names, aliases, generated code, dependency injection registrations, reflection strings, configuration, and test doubles that refer to System.Data.SqlClient.
Don't replace the general System.Data or System.Data.Common namespaces. Microsoft.Data.SqlClient continues to use ADO.NET types such as CommandType, DbType, IsolationLevel, DataTable, DbConnection, and DbCommand from those namespaces.
Some SQL Server-specific types move to other Microsoft.Data namespaces:
| Type | Previous namespace | Microsoft.Data.SqlClient namespace |
|---|---|---|
SqlDataRecord, SqlMetaData |
Microsoft.SqlServer.Server |
Microsoft.Data.SqlClient.Server |
SqlFileStream |
System.Data.SqlTypes |
Microsoft.Data.SqlTypes |
SqlNotificationRequest |
System.Data.Sql |
Microsoft.Data.Sql |
OperationAbortedException |
System.Data |
Microsoft.Data |
In Microsoft.Data.SqlClient 5.0 and later, other SQL Server common language runtime (CLR) types remain in Microsoft.SqlServer.Server. Update each type from compiler errors and the Microsoft.Data.SqlClient API reference, rather than replacing the entire namespace.
Update .NET Framework configuration
An application that resolves providers through DbProviderFactories might need a provider registration in App.config or Web.config:
<configuration>
<system.data>
<DbProviderFactories>
<add name="SqlClient Data Provider"
invariant="Microsoft.Data.SqlClient"
description=".NET data provider for SQL Server"
type="Microsoft.Data.SqlClient.SqlClientFactory, Microsoft.Data.SqlClient" />
</DbProviderFactories>
</system.data>
</configuration>
Update code that requests the provider invariant name:
DbProviderFactory factory =
DbProviderFactories.GetFactory("Microsoft.Data.SqlClient");
Don't add this configuration when the application creates SqlConnection directly and doesn't use DbProviderFactories.
Review encryption and certificate validation
Microsoft.Data.SqlClient uses more secure defaults than System.Data.SqlClient.
| Behavior | System.Data.SqlClient | Microsoft.Data.SqlClient |
|---|---|---|
| Default encryption | Encrypt=false |
Encrypt=true starting with version 4.0 |
| Server certificate validation | Validates the certificate only when client encryption is enabled | Starting with version 2.0, validates the certificate according to TrustServerCertificate when the server forces encryption, even if Encrypt=false |
| Strict encryption | Not supported | Encrypt=Strict starting with version 5.0 for TDS 8.0-capable servers |
SqlConnectionStringBuilder.Encrypt type |
bool |
SqlConnectionEncryptOption starting with version 5.0 |
Don't set Encrypt=false or TrustServerCertificate=true as a general migration fix. Configure a certificate that the client trusts and use a server name that matches the certificate. Use TrustServerCertificate=true only for controlled development environments where validation isn't possible.
The change to SqlConnectionEncryptOption is source-compatible in common assignments through implicit conversions, but it's a binary breaking change. Recompile every assembly that accesses SqlConnectionStringBuilder.Encrypt.
For details, see Encryption and certificate validation.
Review connection strings
Microsoft.Data.SqlClient adds keywords and aliases that System.Data.SqlClient doesn't recognize. For example, it accepts aliases with spaces such as Application Intent and Multi Subnet Failover.
Don't build a connection string with Microsoft.Data.SqlClient.SqlConnectionStringBuilder and then pass it to System.Data.SqlClient. During a staged migration, keep each connection string builder paired with its provider.
Review authentication, encryption, retry, failover, and certificate keywords against Connection string syntax.
Review parameter behavior
Test date and time parameters explicitly:
| Parameter | System.Data.SqlClient behavior | Microsoft.Data.SqlClient behavior |
|---|---|---|
DbType.Time with a DateTime value |
Accepts the value | Use a TimeSpan value |
DbType.Date with a DateTime value |
Can send date and time components | Truncates the time components |
Specify SqlDbType, length, precision, and scale for parameters where SQL Server type inference can change query plans or conversion behavior. Don't use AddWithValue as a migration shortcut when the database type is known.
Check transitive provider references
A direct package removal doesn't guarantee that System.Data.SqlClient is gone. Run:
dotnet list package --include-transitive
If both providers remain:
- Identify the package that brings in
System.Data.SqlClient. - Update or replace that dependency when possible.
- Keep provider-specific types inside the dependency boundary when both must remain.
- Use explicit namespace aliases only as a temporary aid. Don't pass a connection, transaction, parameter, or reader from one provider to the other.
Pay particular attention to SQL Server CLR type libraries and older data access frameworks that expose System.Data.SqlClient types in their public APIs.
Review globalization behavior
.NET Framework and .NET versions before .NET 5 use National Language Support (NLS) globalization on Windows. Current .NET versions use International Components for Unicode (ICU) by default across Windows, Linux, and macOS.
This runtime difference can change some SqlString comparisons. SQL Server uses NLS comparison behavior. If client-side SqlString comparisons must match server behavior, test affected values and review Globalization and ICU. An application can use NLS instead of ICU when required.
Globalization-invariant mode isn't supported by Microsoft.Data.SqlClient.
Validate the migrated application
Build and test on every supported target framework and operating system.
Validate:
- Package restore and published output.
- SQL authentication, Windows integrated authentication, and Microsoft Entra authentication used by the application.
- TLS negotiation, certificate validation, and connection string parsing.
- Connection pooling and access token refresh.
- Parameter types, null values, precision, scale, date, and time behavior.
- Transactions, cancellation, timeouts, retries, and failover.
- Always Encrypted, SQL Server CLR types, bulk copy, query notifications, and other provider-specific features used by the application.
- Logging, counters, tracing, and exception handling.
Run representative queries against every supported database engine version. A successful compile doesn't validate connection security, runtime dependencies, or data conversions.