SqlClient: Encrypt=false not working

Describe the bug

I am trying to connect to SQL Server using Encrypt=False but I cannot get it to work. SQL Server is 2016 placed on Windows Server and configured to not require encryption.

Connection string used:

Data Source=hostname\\aaa;Initial Catalog=SampleDB;User ID=sa;Password=Sample123;Pooling=True;Min Pool Size=3;Max Pool Size=10;Connect Timeout=5;Trust Server Certificate=False;Encrypt=false;
Exception message:
Unhandled exception. Microsoft.Data.SqlClient.SqlException (0x80131904): A connection was successfully established with the server, but then an error occurred during the pre-login handshake. (provider: SSL Provider, error: 31 - Encryption(ssl/tls) handshake failed)
 ---> System.IO.IOException:  Received an unexpected EOF or 0 bytes from the transport stream.

Further technical details

Microsoft.Data.SqlClient version: 4.1.0 .NET target: 6.0 SQL Server version: (e.g. SQL Server 2016) Operating system: Alpine Linux .NET 6 Runtime container

Additional context This does not happen when the client is a Windows machine. .NET 3.1 based service works without any issue

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Comments: 21 (11 by maintainers)

Most upvoted comments

In my case, I was running mssql/server:2019-later in Docker on an Azure Pipelines build agent.

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

Encrypt=False in the connection string did not help.

From SQL logs, it turned out the problem was with the mounted volumes: ERROR: BootstrapSystemDataDirectories. This is a known issue: https://github.com/microsoft/mssql-docker/issues/602#issuecomment-629193915

By not mounting Docker volumes, I could connect. So the original error message threw me off in the wrong direction, debugging SSL and TLS1.2.

Maybe this helps some others googling this.

I would like option to just disable Encryption also in the Login

I assumed this wasn’t possible but I thought I should check and see why. So i looked at the spec and interestingly it says:

The TDS server receives the first packet from the client. The packet SHOULD be a PRELOGIN packet to set up context for login. A Pre-Login message is indicated by the PRELOGIN (0x12) message type described in section 2. The TDS server SHOULD close the underlying transport connection, indicate an error to the upper layer, and enter the “Final State” state, if the first packet is not a structurally correct PRELOGIN packet or if the PRELOGIN packet does not contain the client version as the first option token. Otherwise, the TDS server MUST do one of the following: § Return to the client a PRELOGIN structure wrapped in a table response (0x04) packet and enter “TLS/SSL Negotiation” state if encryption is negotiated. § Return to the client a PRELOGIN structure wrapped in a table response (0x04) packet and enter unencrypted “Login Ready” state if encryption is not negotiated.

So in theory if the server allows no encryption and the client allows no encryption then it is possible to skip the login encryption. However looking at the code for this library I found that:

https://github.com/dotnet/SqlClient/blob/38dfaaa8167024e8e00632569f1c2e3db5f47ef1/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs#L900-L905

So even if the client requests no encryption and the server would allow it we force login to be encrypted to protect the credentials being used. I think this is a good idea and the uses cases for totally disabling encryption aren’t good. Is there compelling reason that you can’t simply change the container security?