SqlClient: A connection was successfully established with the server, but then an error occurred during the pre-login handshake.

Describe the bug

After I update the Microsoft.Data.SqlClient from 3.0.1 to 4.0.1 when I try to access the database I’m getting

Exception message:
Stack trace:

Microsoft.Data.SqlClient.SqlException (0x80131904): A connection was successfully established with the server, but then an error occurred during the pre-login handshake. (provider: TCP Provider, error: 35 - An internal exception was caught)
 ---> System.Security.Authentication.AuthenticationException: The remote certificate was rejected by the provided RemoteCertificateValidationCallback.
   at System.Net.Security.SslStream.SendAuthResetSignal(ProtocolToken message, ExceptionDispatchInfo exception)
   at System.Net.Security.SslStream.CompleteHandshake(SslAuthenticationOptions sslAuthenticationOptions)
   at System.Net.Security.SslStream.ForceAuthenticationAsync[TIOAdapter](TIOAdapter adapter, Boolean receiveFirst, Byte[] reAuthenticationData, Boolean isApm)
   at System.Net.Security.SslStream.AuthenticateAsClient(SslClientAuthenticationOptions sslClientAuthenticationOptions)
   at System.Net.Security.SslStream.AuthenticateAsClient(String targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, Boolean checkCertificateRevocation)
   at Microsoft.Data.SqlClient.SNI.SNITCPHandle.EnableSsl(UInt32 options)
   at Microsoft.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternal& connection)
   at Microsoft.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal& connection)
   at Microsoft.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, DbConnectionInternal& connection)
   at Microsoft.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
   at Microsoft.Data.ProviderBase.DbConnectionClosed.TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
   at Microsoft.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry, SqlConnectionOverrides overrides)
   at Microsoft.Data.SqlClient.SqlConnection.Open(SqlConnectionOverrides overrides)
   at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerConnection.OpenDbConnection(Boolean errorsExpected)
   at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenInternal(Boolean errorsExpected)
   at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.Open(Boolean errorsExpected)
   at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerDatabaseCreator.<>c__DisplayClass18_0.<Exists>b__0(DateTime giveUp)
   at Microsoft.EntityFrameworkCore.ExecutionStrategyExtensions.<>c__DisplayClass12_0`2.<Execute>b__0(DbContext c, TState s)
   at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)
   at Microsoft.EntityFrameworkCore.ExecutionStrategyExtensions.Execute[TState,TResult](IExecutionStrategy strategy, TState state, Func`2 operation, Func`2 verifySucceeded)
   at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerDatabaseCreator.Exists(Boolean retryOnNotExists)
   at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerDatabaseCreator.Exists()
   at Microsoft.EntityFrameworkCore.Migrations.HistoryRepository.Exists()
   at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.Migrate(String targetMigration)
   at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.UpdateDatabase(String targetMigration, String connectionString, String contextType)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.UpdateDatabaseImpl(String targetMigration, String connectionString, String contextType)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.UpdateDatabase.<>c__DisplayClass0_0.<.ctor>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
ClientConnectionId:51a7429a-eee3-4ee4-802e-be6c50c1129b
Error Number:-2146893019,State:0,Class:20

Expected behavior

Connect to database

Further technical details

Microsoft.Data.SqlClient version: 4.0.1 .NET target: .NET 6.0 on MacOS SQL Server version: Microsoft SQL Server 2019 (RTM-CU14) (KB5007182) - 15.0.4188.2 (X64) Developer Edition (64-bit) on Linux (Ubuntu 20.04.3 LTS) <X64> Operating system: Docker Linux

Additional context I’m running EF Core 6.0.1 migrations

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 1
  • Comments: 31 (4 by maintainers)

Commits related to this issue

Most upvoted comments

Have you tried to set TrustServerCertificate=True in your connection string ?

@lillo42 have your tried adding Encrypt=false to your connection string? or as mentioned above TrustServerCertificate=True

@JRahnama and @alaincroisetiere when I add TrustServerCertificate=True or Encrypt=false works, why I need to added it now?

We are experiencing the same problem trying to access a SQL Server from a .NET 5 microservice deployed on OpenShift. The version of the Microsoft.Data.SqlClient is 4.1.0.

We solved this by adding the following parameters in the connection string:

TrustServerCertificate=True;MultiSubnetFailover=True

This connection string works for me "Data Source=localhost; TrustServerCertificate=True; MultiSubnetFailover=True; Initial Catalog=YourDB; User ID='sa'; Password='YourPass';"

Have you tried to set TrustServerCertificate=True in your connection string ?

Thanks, I added TrustServerCertificate=True; to the connection string and it worked

@stijnherreman for development and localhost you can use Encrypt=false in your connection string.

I was runned in this issue for both System.Data.SqlClient Microsoft.Data.SqlClient on Android 11.0 - API 30. Encrypt, TrustServerCertificate and MultiSubnetFailover flags set to true are not helped for me. On Windows work as expected.

server version: Microsoft SQL Server 2019 (RTM) - 15.0.2000.5 (X64) Sep 24 2019 13:48:23 Copyright © 2019 Microsoft Corporation Standard Edition (64-bit) on Windows Server 2019 Standard 10.0 <X64> (Build 17763: ) (Hypervisor)

Here is my exception message: A connection was successfully established with the server, but then an error occurred during the pre-login handshake. (provider: TCP Provider, error: 35 - An internal exception was caught)

I had the same issue, as a workaround I suggest switching to System.Data.SqlClient, it works as expected

System.Data.SqlClient is in servicing mode and is not updating on regular basis, but for addressing security issues and important updates. We suggest using Microsoft.Data.SqlClient as active ADO.NET library which gets updated and implements new features.

By changing this behavior, two issues has been addressed :

Default Encrypt to True. This is for security. Similar to http/https, if the client starts with allowing non-encrypted connections, it will always be susceptible to MITM attacks. Even if the server is configured to require encryption, there can be a MITM altering the server’s response to say it doesn’t require encryption. The MITM can then proxy the connection. client <-plain text-> MITM <-encrypted-> server = the connection is compromised.

Security has been encouraging us for years to change the default behavior of client drivers to be secure by default and we have resisted, knowing that it is a breaking change for most users. It’s easy enough for developers to add Encrypt = false to all their connection strings, if they need to. We just want to make sure they understand the choice they are making and they are making it deliberately. With cloud computing becoming more and more common, it’s not safe to leave the default value of Encrypt equal to false.

The less-breaking, but still important, fix here is to ensure connections fail if the client does not have any encryption libraries available and either Encrypt = true or the server requires encryption. SqlClient + native SNI is the only MS driver we’ve found that will successfully connect in that scenario.

Have you tried to set TrustServerCertificate=True in your connection string ?

This worked for me. Thanks!

@alaincroisetiere Thanks, I haven’t saw the breaking changes parts

I had the same issue, as a workaround I suggest switching to System.Data.SqlClient, it works as expected