Skip to content

Stable Release v7.1.0

Choose a tag to compare

@paulmedynski paulmedynski released this 18 Sep 17:26
· 10 commits to release/7.1 since this release
744f4f0

This is the general availability release of Microsoft.Data.SqlClient 7.1. It closes out the 7.1 preview cycle with application identity reporting for telemetry, the deprecation of TransparentNetworkIPResolution, and a set of connection, transaction, and Named Pipes fixes.

Important — package version alignment: Starting with the 7.0.2 release, the Microsoft.Data.SqlClient driver and its companion packages share a single aligned version. The 7.1.0 GA release continues this alignment; the following packages ship together as 7.1.0:

  • Microsoft.Data.SqlClient
  • Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider
  • Microsoft.Data.SqlClient.Extensions.Azure
  • Microsoft.Data.SqlClient.Extensions.Abstractions
  • Microsoft.Data.SqlClient.Internal.Logging

(Microsoft.SqlServer.Server continues to version independently and remains at 1.0.0.)

Applications must reference the same versions of Microsoft.Data.SqlClient and its extensions for best compatibility. In particular, applications that reference Microsoft.Data.SqlClient.Extensions.Azure must upgrade it to 7.1.0 when upgrading Microsoft.Data.SqlClient to 7.1.0.

Compatibility guarantee: All aligned assemblies ship with FileVersion 7.1.0.x and AssemblyVersion 7.0.0.0. The AssemblyVersion is unchanged from 7.0.2, so upgrading from 7.0.2, 7.0.3, or any 7.1 preview to 7.1.0 does not require any new .NET Framework strong-name binding redirects. Applications upgrading from 7.0.0 or 7.0.1 should note that Extensions.Azure, Extensions.Abstractions, and Internal.Logging raised their AssemblyVersion from 1.0.0.0 to 7.0.0.0 in 7.0.2; see those release notes for the one-time .NET Framework impact.

Companion package release notes

Changes Since 7.1.0-preview3

Added

Application Identity in the USERAGENT Payload

What Changed:

  • Added a RegisteredApplication enum and a matching SqlConnection.RegisteredApplication property that let a library or tool identify itself to SQL Server through version 2 of the TDS USERAGENT feature extension. The payload also carries a new driver-owned 64-bit Driver Properties flag field; bit 0 reports whether connection pool V2 is enabled for the process. Both fields are emitted as unpadded uppercase hexadecimal. (#3201, #4632)

Who Benefits:

  • Middleware and tooling built on top of the driver — Entity Framework Core, Semantic Kernel, SQL Server Management Studio, SqlPackage, Data API Builder, and similar — can be distinguished in server-side telemetry without the driver accepting arbitrary user-supplied user-agent text. This originated as a request from the Entity Framework Core team.
  • Service operators gain a more accurate picture of which client stacks are connecting, which helps when diagnosing workload-specific behavior.

Impact:

  • Purely additive from the application's perspective: a newly created physical connection whose RegisteredApplication is unset reports Unknown (0). On the wire the field itself is new — USERAGENT payload v1 carried no application identifier, while v2 always emits one.
  • Set the property before calling Open or OpenAsync. Assigning it while the connection is connecting or open throws InvalidOperationException.
using var connection = new SqlConnection(connectionString);
connection.RegisteredApplication = RegisteredApplication.EntityFrameworkCore;
await connection.OpenAsync();
  • The enum is ushort-backed and marked [CLSCompliant(false)]. Values are partitioned by range: 0x0001–0x7FFF for Microsoft-defined large-scale applications, 0x8000–0xBFFF for small-scale use, and 0xC000–0xFFFF for public/developer use. Applications that are not yet registered can cast an unassigned value from the appropriate range.
  • Application identity is client-supplied telemetry and must never be used for authorization or any other security decision.
  • The value is not part of the connection pool key. A pooled physical connection reports the application that originally created it, and background Min Pool Size connections report Unknown. Cloned connections preserve the value.

Changed

TransparentNetworkIPResolution Is Now Obsolete

What Changed:

  • SqlConnectionStringBuilder.TransparentNetworkIPResolution is now marked [Obsolete]. The obsoletion message directs callers to MultiSubnetFailover and notes that Transparent Network IP Resolution (TNIR) is a .NET Framework-only feature. (#4494, #4576)

Who Benefits:

  • Applications still relying on TNIR get a compile-time signal to move to MultiSubnetFailover, which addresses the same "connect quickly across multiple DNS-resolved addresses" goal, works consistently on every supported target framework, and is the documented strategy for Always On availability group listeners.

Impact:

  • No runtime behavior change. TNIR still defaults to true on .NET Framework, and MultiSubnetFailover still defaults to false. The property remains .NET Framework-only and is not exposed on modern .NET, where a connection string containing the Transparent Network IP Resolution keyword still throws NotSupportedException. No new AppContext switches were introduced.
  • The only visible effect is a new CS0618 build warning for code that references the property. Suppress it, or migrate to MultiSubnetFailover, at your own pace. Flipping the TNIR and MultiSubnetFailover defaults is deferred to a future major version.

Other changes

  • Updated Microsoft.Data.SqlClient.SNI and Microsoft.Data.SqlClient.SNI.runtime to v7.1.0 (was v7.1.0-preview3.26226.3). (#4698)
  • Unified the exception message raised when conflicting token-based and SSPI authentication properties are set on the same SqlConnection, and documented the complete set of properties that conflict with AccessToken. (#4629)
  • Documentation corrections:
    • Rewrote the SqlDataRecord and SqlMetaData documentation, which incorrectly described the SQL CLR-only SqlContext and SqlPipe types, and clarified whether SqlDataRecord instances can be reused. (#1805, #4440)
    • Corrected the LCID 1033 sample comment to use the official Windows locale name English (United States). (#4646)

Fixed

  • Fixed a pooled connection being returned to the pool in a broken state after a TransactionScope rollback — for example, when distributed transaction promotion fails on .NET 8+ where implicit distributed transactions are disabled by default. A subsequent Open() succeeded but BeginTransaction() threw InvalidOperationException ("the connection has been broken"). Connection reset now preserves the transaction when the pooled connection is either a delegated transaction root or enlisted in a transaction, instead of only the latter. (#4001, #4557)
  • Fixed GetSchema("DataTypes") never reporting the SQL Server 2025 json type against Azure SQL. The row was filtered by a string comparison against a minimum server version of 17.00.000.0, which Azure SQL can never satisfy because it always reports 12.00.xxxx. The decision now uses the json support flag negotiated through the TDS FEATUREEXTACK token, which is accurate on both Azure SQL and on-premises SQL Server 2025+. (#4592, #4682)
  • Fixed a malformed UNC pipe path being composed for IPv6 literal server names over Named Pipes in managed SNI (for example Server=np:::1, Server=np:[::1], or Server=\\::1\pipe\sql\query). A UNC path component may not contain a colon, and handing such a path to the OS could trigger an access violation inside LSASS on Windows, forcing a reboot. IPv6 literals are now transcribed to their .ipv6-literal.net form as defined by MS-DTYP 2.2.57, and a colon-bearing host with no valid IPv6 interpretation now fails with the standard invalid-connection-string error. Colon-free host names, LocalDB, localhost, ., and IPv6 over TCP are unaffected. (net8.0/net9.0 only — this is the managed SNI counterpart to the native SNI fix) (#4523, #4558)
  • Fixed configurable retry logic installing a permanent, process-wide assembly-resolution handler that could interfere with unrelated assembly loading. The handler is now installed only while an explicitly configured custom retry provider is being resolved and constructed, and it probes AppContext.BaseDirectory instead of the current working directory. Place custom retry assemblies in the application base directory; dependencies loaded after provider construction must be resolvable through normal application dependency resolution or an application-supplied handler. (net8.0/net9.0 only — the .NET Framework path does not use AssemblyLoadContext) (#2214, #4547)
  • Fixed open/close throughput regressions in the opt-in connection pool V2 (Switch.Microsoft.Data.SqlClient.UseConnectionPoolV2). Acquiring an already-pooled connection no longer dispatches to the thread pool before attempting an inline, non-blocking acquisition, no longer allocates a timer-backed CancellationTokenSource before it is known that the caller will wait, and no longer allocates a Task on the synchronous completion path. The default pool is unaffected. (#4543)

Cumulative Changes Since 7.0.3

This section summarizes all changes across the 7.1 preview cycle for users upgrading from the latest 7.0 stable release. Changes that were also serviced into 7.0.1, 7.0.2, or 7.0.3 are omitted — they are already present for 7.0.x users.

Added

SqlBatch Support on .NET Framework (net462 only)

What Changed:

  • SqlBatch, SqlBatchCommand, and the related execution methods are now available on the .NET Framework target, so the batching API spans the full supported platform matrix. (#3926)

Who Benefits:

  • Libraries and applications that multi-target .NET Framework and modern .NET can use a single data-access surface instead of maintaining separate batching strategies.

Impact:

  • Purely additive; existing SqlCommand code is unchanged.

SqlConnection.GetSchemaAsync

What Changed:

  • Added asynchronous overloads of SqlConnection.GetSchema that mirror the existing synchronous shapes and honor a supplied CancellationToken. The .NET Framework schema code paths were unified with the .NET implementation in the process. (#3005)

Who Benefits:

  • Applications that enumerate database metadata as part of a request pipeline no longer block a thread on synchronous I/O.

Impact:

  • Additive; existing GetSchema(...) calls are unchanged.

Asynchronous Key Store Provider APIs for Always Encrypted

What Changed:

  • Added four virtual asynchronous counterparts to the synchronous methods on SqlColumnEncryptionKeyStoreProvider: DecryptColumnEncryptionKeyAsync, EncryptColumnEncryptionKeyAsync, SignColumnMasterKeyMetadataAsync, and VerifyColumnMasterKeyMetadataAsync. Each accepts an optional CancellationToken, and the default implementations delegate to the existing synchronous methods. (#3672, #3673)

Who Benefits:

  • Authors of custom key store providers backed by network-bound stores such as HSMs or cloud key vaults can implement genuinely asynchronous key operations.

Impact:

  • Purely additive; existing providers compile and run unmodified.
  • Introduced, but not yet consumed by the driver. The driver's own column encryption key resolution path still invokes the synchronous provider methods on both the synchronous and asynchronous command paths. A future release will enable their use from the driver's own asynchronous APIs.
  • The in-box SqlColumnEncryptionAzureKeyVaultProvider overrides all four methods. See the AzureKeyVaultProvider 7.1.0 release notes. (#4540)

Configurable Idle Connection Timeout

What Changed:

  • Added a Connection Idle Timeout connection-string keyword and matching SqlConnectionStringBuilder.IdleTimeout property that let the pool evict connections whose idle time exceeds the configured value. The default is 300 seconds; 0 disables idle expiration and negative values throw ArgumentException. Enforcement is gated on Switch.Microsoft.Data.SqlClient.UseLegacyIdleTimeoutBehavior, which defaults to true to preserve historical pooling behavior. (#4295)

Who Benefits:

  • Applications running against Azure SQL Database and other elastic backends can bound connection idle time to align with server-side session recycling and reduce stale-connection failures.

Impact:

  • Default behavior is unchanged: the keyword is parsed but not enforced until the legacy switch is set to false.

Connection Pool V2 Feature Completeness

What Changed:

  • Substantially expanded ChannelDbConnectionPool, the opt-in pool behind Switch.Microsoft.Data.SqlClient.UseConnectionPoolV2, bringing it to parity with the default WaitHandleDbConnectionPool: transaction support, broken-connection replacement, background warmup and replenishment to Min Pool Size, idle pruning derived from Connection Idle Timeout, optional connection-creation rate limiting, leaked-connection reclamation, and metrics/tracing parity. (#4395, #4396, #4429, #4452, #4463, #4487, #4504, #4529, #4543)
  • SqlConnection.ClearPool(SqlConnection) and SqlConnection.ClearAllPools() now work correctly under pool V2. (#4194)

Who Benefits:

  • Applications evaluating the V2 pool can exercise transaction-enlisted workloads, broken-connection recovery, leaked-connection reclamation, and pool warmup, and can observe the pool through the existing performance counters and EventSource traces.

Impact:

  • No change to default behavior. Connection pool V2 remains in evaluation and is used only when the AppContext switch is enabled.

Other additions

  • Added application identity reporting through SqlConnection.RegisteredApplication and USERAGENT payload version 2 (see Changes Since 7.1.0-preview3 above). (#4632)
  • SqlBulkCopy column mappings now accept the SQL Graph pseudo-column aliases $node_id, $edge_id, $from_id, and $to_id as destination column names. (#3677)
  • SqlBatchCommand.CommandBehavior is now honored inside a SqlBatch, and SqlBatch.ExecuteReader respects the CommandBehavior passed to it. Batches that previously set the property and relied on it being ignored will now see it applied. (#4125)
  • Added connection-string synonyms for better compatibility with other SQL Server drivers: ColumnEncryption, ConnectTimeout, FailoverPartner, PacketSize, and WorkstationId. (#4192)
  • Added the SQL Server 2025 json data type to the DataTypes collection returned by SqlConnection.GetSchema. (#3858)

Changed

Connection Timeout Can Now Propagate Through the Pool

What Changed:

  • Replaced raw TimeSpan timeouts with a shared TimeoutTimer across SqlConnection.Open[Async], pool acquisition, and physical connection creation, so the Connect Timeout budget can be deducted while a request waits in the pool. Enforcement is gated on Switch.Microsoft.Data.SqlClient.UseOverallConnectTimeoutForPoolWait, which defaults to false. Introduces a dependency on Microsoft.Bcl.TimeProvider. (#4270)

Who Benefits:

  • Applications that observe pool contention can opt in to having the configured Connect Timeout respected end-to-end instead of the budget effectively restarting when a physical connection is eventually opened.

Impact:

  • Default behavior is unchanged. When the switch is enabled, Open/OpenAsync under heavy pool contention may surface timeouts sooner than before; successful opens are unaffected.

TransparentNetworkIPResolution Is Now Obsolete

  • See Changes Since 7.1.0-preview3 above. (#4494, #4576)

Other changes

  • Windows-only native SNI types are now removed cleanly by the IL trimmer on Linux and macOS, and LocalAppContextSwitches.UseManagedNetworking is substituted for a constant. The driver builds a single OS-agnostic assembly for all platforms; NuGet package structure and contents are unchanged. (#4207, #4239, #4465, #4474)
  • Performance and allocation improvements:
    • Restored reuse of PacketData linked-list nodes via a bounded free list on StateSnapshot, returning SqlCommand/ExecuteReaderAsync from +120.9% allocated against the 6.1.6 baseline to +0.1%. (#4536)
    • SqlBulkCopy no longer builds SQL Graph column alias mapping tables when neither the source nor destination table contains graph pseudo-columns. (#4535)
    • Reduced allocations when sending large string values to SQL Server, when reading SqlErrorCollection counters with no errors present, and on expected null-return paths that previously materialized stack traces. (#4072, #4157, #4099, #4102)
    • Use hardcoded LCID mappings when decoding strings, avoiding repeated culture lookups. (#4212)
  • Internal hardening and refactoring:
    • SqlConnection internal state transitions now use Interlocked.CompareExchange guards. (#4267)
    • Removed legacy connection-options inheritance from internal APIs and refactored ForceNewConnection handling. (#4235, #4237, #4261, #4415)
    • Added async generic helpers to reduce duplication across sync/async code paths. (#4334)
  • SqlVector<float> now serializes and deserializes little-endian multibyte values explicitly for consistent behavior across architectures. (#3861)
  • Improved EnclaveDiffieHellmanInfo.Size accuracy. (#4346)
  • Documentation corrections for SqlDataRecord, SqlMetaData, server certificate configuration, and the LCID 1033 locale name. (#4408, #4440, #4646)
  • Updated Dependencies:
    • Updated Microsoft.Bcl.Cryptography, Microsoft.Extensions.Caching.Memory, System.Configuration.ConfigurationManager, and System.Security.Cryptography.Pkcs to v9.0.18 for the net9.0 target framework. Non-net9.0 targets keep their existing 8.0.x pins. (#4507)
    • Added System.Threading.RateLimiting and Microsoft.Bcl.TimeProvider to the packaged dependency metadata. (#4270, #4507)
    • Updated Microsoft.Data.SqlClient.SNI and Microsoft.Data.SqlClient.SNI.runtime to v7.1.0 (was v6.0.3). (#4564, #4698)

Fixed

  • Fixed Always Encrypted reads of CekMdVersion and EkValueCount to align with the TDS specification. (#4240)
  • Fixed an OverflowException when sending large decimal values (for example decimal.MaxValue) as a parameter with explicit Precision and Scale. This primarily affected Always Encrypted scenarios, where both must always be set. (#1655, #4443)
  • Fixed a TDS stream error when passing a DateOnly value as a parameter with SqlDbType.Variant, and fixed DateOnly values written to a sql_variant column of a table-valued parameter being sent as datetime instead of date (which also caused overflows for values valid for date but out of range for datetime). Reading continues to return DateTime instances by default for backwards compatibility. (net8.0/net9.0 only — .NET Framework has no DateOnly type) (#3953, #3934, #4294, #4439)
  • Fixed a SqlConnectionFactory timer that woke the process every 30 seconds for the lifetime of the application even when no connection pools existed — including with Pooling=False and after ClearAllPools(). The pruning timer is now armed on demand and disarmed once there is nothing left to prune. A missing .NET Framework unload hook was also added. (#1881, #4479)
  • Fixed connection pool performance counter defects affecting the default pool as well as pool V2. active-soft-connects and number-of-active-connections could go negative after a failed connection activation, and active-soft-connects, active-hard-connections, and number-of-pooled-connections drifted upward permanently after a broken connection was replaced. (#4504)
  • Fixed a pooled connection being returned to the pool in a broken state after a TransactionScope rollback, which caused a later BeginTransaction() to throw InvalidOperationException. (#4001, #4557)
  • Fixed GetSchema("DataTypes") never reporting the json type against Azure SQL. (#4592, #4682)
  • Fixed a malformed UNC pipe path being composed for IPv6 literal server names over Named Pipes in managed SNI, which could trigger an LSASS access violation and a forced reboot on Windows. (net8.0/net9.0 only) (#4523, #4558)
  • Fixed several async entry points in SqlBulkCopy, SqlDataReader.InvokeAsyncCall, SqlCommand.Reader, and SqlCommand.Xml that captured fatal exceptions such as OutOfMemoryException into faulted Tasks instead of letting them propagate. (#4437)
  • Fixed a SqlDataReader streaming bug where calling IsDBNull() before reading a streamed value could skip column data. (#4082)
  • Fixed a race in SqlConnection.TryOpenInner that could surface as InvalidCastException; the same race now returns a deterministic InvalidOperationException. (#4179)
  • Fixed LoginWithFailover to validate parser state before continuing, preventing null-reference failures during failover login. (#4140)
  • Fixed the SPN used during login to use the resolved port instead of the instance name when Protocol=None or Protocol=Admin is specified. (#4180)
  • Fixed several CancellationTokenSource leaks in SqlDataReader, SqlConnection, the SqlCommand reconnect paths, and the sequential-stream helpers. (#4009)

Removed

SQL Server 7.0 and 2000 Support

What Changed:

  • Removed dead protocol-level code paths for SQL Server 7.0 and SQL Server 2000, along with the now-orphaned SQL Server 2000 type-system compatibility option. The TypeSystem.SQLServer2000 enum value and the Type System Version=SQL Server 2000 connection-string branch are gone. (#4015)

Who Benefits:

  • The driver no longer carries dead legacy code, and the documented connection-string surface (Latest, SQL Server 2005, SQL Server 2008, SQL Server 2012) now matches the implementation exactly.

Impact:

  • Breaking: A connection string that specifies Type System Version=SQL Server 2000 now throws ArgumentException when the connection is opened. Switch to a supported value such as Latest. There is no change to which servers the driver connects to — SQL Server 7.0 and 2000 were already rejected during login version negotiation.

Contributors

We thank the following public contributors. Their efforts toward this project are very much appreciated.

Target Platform Support

  • .NET Framework 4.6.2+ (Windows x86, Windows x64, Windows ARM64)
  • .NET 8.0+ (Windows x86, Windows x64, Windows ARM, Windows ARM64, Linux, macOS)

Dependencies

.NET 9.0

  • Microsoft.Bcl.Cryptography 9.0.18
  • Microsoft.Data.SqlClient.Extensions.Abstractions 7.1.0
  • Microsoft.Data.SqlClient.Internal.Logging 7.1.0
  • Microsoft.Data.SqlClient.SNI.runtime 7.1.0
  • Microsoft.Extensions.Caching.Memory 9.0.18
  • Microsoft.IdentityModel.JsonWebTokens 8.16.0
  • Microsoft.IdentityModel.Protocols.OpenIdConnect 8.16.0
  • Microsoft.SqlServer.Server 1.0.0
  • System.Configuration.ConfigurationManager 9.0.18
  • System.Security.Cryptography.Pkcs 9.0.18
  • System.Threading.RateLimiting 9.0.18

.NET 8.0

  • Microsoft.Bcl.Cryptography 8.0.0
  • Microsoft.Data.SqlClient.Extensions.Abstractions 7.1.0
  • Microsoft.Data.SqlClient.Internal.Logging 7.1.0
  • Microsoft.Data.SqlClient.SNI.runtime 7.1.0
  • Microsoft.Extensions.Caching.Memory 8.0.1
  • Microsoft.IdentityModel.JsonWebTokens 8.16.0
  • Microsoft.IdentityModel.Protocols.OpenIdConnect 8.16.0
  • Microsoft.SqlServer.Server 1.0.0
  • System.Configuration.ConfigurationManager 8.0.1
  • System.Security.Cryptography.Pkcs 8.0.1
  • System.Threading.RateLimiting 8.0.0

.NET Standard 2.0

  • Microsoft.Bcl.Cryptography 8.0.0
  • Microsoft.Bcl.TimeProvider 8.0.1
  • Microsoft.Data.SqlClient.Extensions.Abstractions 7.1.0
  • Microsoft.Data.SqlClient.Internal.Logging 7.1.0
  • Microsoft.Data.SqlClient.SNI.runtime 7.1.0
  • Microsoft.Extensions.Caching.Memory 8.0.1
  • Microsoft.IdentityModel.JsonWebTokens 8.16.0
  • Microsoft.IdentityModel.Protocols.OpenIdConnect 8.16.0
  • Microsoft.SqlServer.Server 1.0.0
  • System.Configuration.ConfigurationManager 8.0.1
  • System.Security.Cryptography.Pkcs 8.0.1
  • System.Text.Json 10.0.3
  • System.Threading.Channels 10.0.3
  • System.Threading.RateLimiting 8.0.0

.NET Framework 4.6.2+

  • Microsoft.Bcl.Cryptography 8.0.0
  • Microsoft.Bcl.TimeProvider 8.0.1
  • Microsoft.Data.SqlClient.Extensions.Abstractions 7.1.0
  • Microsoft.Data.SqlClient.Internal.Logging 7.1.0
  • Microsoft.Data.SqlClient.SNI 7.1.0
  • Microsoft.Extensions.Caching.Memory 8.0.1
  • Microsoft.IdentityModel.JsonWebTokens 8.16.0
  • Microsoft.IdentityModel.Protocols.OpenIdConnect 8.16.0
  • System.Buffers 4.6.1
  • System.Data.Common 4.3.0
  • System.Diagnostics.DiagnosticSource 10.0.3
  • System.Memory 4.6.3
  • System.Runtime.InteropServices.RuntimeInformation 4.3.0
  • System.Security.Cryptography.Pkcs 8.0.1
  • System.Text.Json 10.0.3
  • System.Threading.Channels 10.0.3
  • System.Threading.RateLimiting 8.0.0
  • System.ValueTuple 4.6.2