Repository navigation
.NET Framework broken in 8.0.8 for first connect #6274
Description
Activity
This really sounds like configuration error, you may have a config file containing your connection details which might be different per build configuration? Are you stating the code sample you provided is enough to reproduce the problem? If so we should have already had a lot more reports.
Reacted by Shay RojanskyI don't think so, since if I change the target of the project to .NET 8, all works fine. I added "it happens only on the very first connect" and "works with .NET 8" to first post.
edit: I see I missed the SSL configuration part.
Additionally I tested my IP address, instead of localhost, same result, to be sure that the windows localhost windows update is not the cause.edit: I tested it on 4 machines, Win10 22H2, Win11 23H2/24H2/25H2
- changed the title
[-].NET Framework broken in 8.0.8[/-][+].NET Framework broken in 8.0.8 for first connect[/+]on Oct 30, 2025 I tried to find the commit since this is the case. It is #4005 / 7ac49cc. The actual root cause are the new assignments in
NpgsqlConnectionStringBuilder.Init(), especiallySslMode = SslMode.Prefer. So appendingSSL Mode=Disableto connection string lead to work again .Means this behavior is since npgsql version 6.
Another dig in finds that TLS1.3 seems not working well in .NET Framework, see #5823. By default disable TLS1.3 for .NET Framework would make sense.
The switch
NpgsqlConnector.DisableSystemDefaultTlsVersionscan only be influenced with registry. Right? This is not what I require.Another dig in finds that TLS1.3 seems not working well in .NET Framework
That's certainly not true, according to official documentation TLS 1.3 is supported starting with .NET Framework 4.6.2. In addition, we enable it if and only if
ServicePointManager.DisableSystemDefaultTlsVersionsis set tofalse, and with this property not existing at least until .NET Framework 4.7 (I only checked the source code for 4.6.2) that means that TLS 1.3 isn't going to be enabled for unsupported versions of .NET Framework.I see, anyway setting
AppContext.SetSwitch("Switch.System.Net.DontEnableSystemDefaultTlsVersions", true);does not fix my issue. I thought initially it could be related.You should check postgres logs, but most likely what happens is that for some reason postgres doesn't allow to authenticate with ssl, in which case it returns an error and immediately breaks the connection. But due to a way how postgres terminates connection and how windows handles it, what happens is that windows receives the error on the socket and also rst packet, and the moment rst packet is read the whole internal buffer is cleared, leading to that error message being lost.
Maybe we should always retry for
prefer/allowinstead of only doing that whenever we get a specific errornpgsql/src/Npgsql/Internal/NpgsqlConnector.cs
Lines 561 to 581 in 43e15ee
catch (PostgresException e) when (e.SqlState == PostgresErrorCodes.InvalidAuthorizationSpecification && (sslMode == SslMode.Prefer && conn.IsSecure || sslMode == SslMode.Allow && !conn.IsSecure)) { cancellationRegistration.Dispose(); Debug.Assert(!conn.IsBroken); conn.Cleanup(); // If Prefer was specified and we failed (with SSL), retry without SSL. // If Allow was specified and we failed (without SSL), retry with SSL await OpenCore( conn, sslMode == SslMode.Prefer ? SslMode.Disable : SslMode.Require, timeout, async, cancellationToken, isFirstAttempt: false).ConfigureAwait(false); return; } @vonzshik Change the catch to just
Exceptionwould fix it. BTW the error in this case is (same line number as b732322):Npgsql.NpgsqlException (0x80004005): Exception while reading from stream ---> System.IO.IOException: Von der Übertragungsverbindung können keine Daten gelesen werden: Eine vorhandene Verbindung wurde vom Remotehost geschlossen. ---> System.Net.Sockets.SocketException: Eine vorhandene Verbindung wurde vom Remotehost geschlossen bei System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size) --- Ende der internen Ausnahmestapelüberwachung --- bei System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size) bei System.Net.FixedSizeReader.ReadPacket(Byte[] buffer, Int32 offset, Int32 count) bei System.Net.Security._SslStream.StartFrameHeader(Byte[] buffer, Int32 offset, Int32 count, AsyncProtocolRequest asyncRequest) bei System.Net.Security._SslStream.StartReading(Byte[] buffer, Int32 offset, Int32 count, AsyncProtocolRequest asyncRequest) bei System.Net.Security._SslStream.ProcessRead(Byte[] buffer, Int32 offset, Int32 count, AsyncProtocolRequest asyncRequest) bei System.Net.Security.SslStream.Read(Byte[] buffer, Int32 offset, Int32 count) bei Npgsql.Internal.NpgsqlReadBuffer.<<Ensure>g__EnsureLong|55_0>d.MoveNext() in \npgsql\src\Npgsql\Internal\NpgsqlReadBuffer.cs:Zeile 330. bei Npgsql.Internal.NpgsqlReadBuffer.<<Ensure>g__EnsureLong|55_0>d.MoveNext() in \npgsql\src\Npgsql\Internal\NpgsqlReadBuffer.cs:Zeile 417. --- Ende der Stapelüberwachung vom vorhergehenden Ort, an dem die Ausnahme ausgelöst wurde --- bei System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() bei System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) bei System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable.ConfiguredValueTaskAwaiter.GetResult() bei Npgsql.Internal.NpgsqlConnector.<ReadMessageLong>d__231.MoveNext() in \npgsql\src\Npgsql\Internal\NpgsqlConnector.cs:Zeile 1465. --- Ende der Stapelüberwachung vom vorhergehenden Ort, an dem die Ausnahme ausgelöst wurde --- bei System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() bei System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) bei System.Threading.Tasks.ValueTask`1.get_Result() bei Npgsql.Internal.NpgsqlConnector.<Authenticate>d__0.MoveNext() in \npgsql\src\Npgsql\Internal\NpgsqlConnector.Auth.cs:Zeile 24. --- Ende der Stapelüberwachung vom vorhergehenden Ort, an dem die Ausnahme ausgelöst wurde --- bei System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() bei System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) bei System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult() bei Npgsql.Internal.NpgsqlConnector.<<Open>g__OpenCore|211_1>d.MoveNext() in \npgsql\src\Npgsql\Internal\NpgsqlConnector.cs:Zeile 559.On Second connect the correct exception appears:
Npgsql.PostgresException (0x80004005): 28000: connection requires a valid client certificate bei Npgsql.Internal.NpgsqlConnector.<ReadMessageLong>d__231.MoveNext() in \npgsql\src\Npgsql\Internal\NpgsqlConnector.cs:Zeile 1458. --- Ende der Stapelüberwachung vom vorhergehenden Ort, an dem die Ausnahme ausgelöst wurde --- bei System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() bei System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) bei System.Threading.Tasks.ValueTask`1.get_Result() bei Npgsql.Internal.NpgsqlConnector.<Authenticate>d__0.MoveNext() in \npgsql\src\Npgsql\Internal\NpgsqlConnector.Auth.cs:Zeile 24. --- Ende der Stapelüberwachung vom vorhergehenden Ort, an dem die Ausnahme ausgelöst wurde --- bei System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() bei System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) bei System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult() bei Npgsql.Internal.NpgsqlConnector.<<Open>g__OpenCore|211_1>d.MoveNext() in \npgsql\src\Npgsql\Internal\NpgsqlConnector.cs:Zeile 559. Exception data: Severity: FATAL SqlState: 28000 MessageText: connection requires a valid client certificate File: auth.c Line: 422 Routine: ClientAuthenticationJust to be clear - the problem here is that an incorrect exception is being thrown on the 1st attempt (and not on the 2nd), on .NET Framework? In other words, it's expected for the connection to fail, and the problem is just the kind of exception?
Whether it's .NET Framework or .NET doesn't really matter, it's just a race condition between us reading the correct error and also reading rst packet, which on windows clears the whole buffer and leads us to being unable to return a correct exception.
In my opinion it is only .NET Framework related. I had in past to do other fixes that get .NET Framework working with SSL. The point of the race condition I have no idea if this is the case, but I do not believe it.
@trivalik you can read more about it in https://www.postgresql.org/message-id/CALDaNm2tEvr_Kum7SyvFn0=6H3P0P-Zkhnd=dkkX+Q=wKutZ=A@mail.gmail.com
I do not say that this could not happen. I do say that in this case probably an issue in .NET Framework implementation lead to this. During my currents tests, I had never issues in .NET 8.
I would be more interested in why we end up getting an RST in the first place, this would also help for .NET 8+.
Reacted by Shay RojanskyI would be more interested in why we end up getting an RST in the first place, this would also help for .NET 8+.
That's how Postgres works, it just drops the connection (and socket). It works fine on linux because there RST doesn't clear the buffer, but on Windows it does.
I do not say that this could not happen. I do say that in this case probably an issue in .NET Framework implementation lead to this. During my currents tests, I had never issues in .NET 8.
Well, just for fun I tried to write a small repro for .NET 9, and it does fail at startup. So again, this has nothing to do with .NET vs .NET Framework, that's a race condition.
Npgsql.NpgsqlException (0x80004005): Exception while reading from stream ---> System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.. ---> System.Net.Sockets.SocketException (10054): An existing connection was forcibly closed by the remote host. at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.CreateException(SocketError error, Boolean forAsyncThrow) at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ReceiveAsync(Socket socket, CancellationToken cancellationToken) at System.Net.Sockets.Socket.ReceiveAsync(Memory`1 buffer, SocketFlags socketFlags, Boolean fromNetworkStream, CancellationToken cancellationToken) at System.Net.Sockets.NetworkStream.ReadAsync(Memory`1 buffer, CancellationToken cancellationToken) at System.Net.Security.SslStream.EnsureFullTlsFrameAsync[TIOAdapter](CancellationToken cancellationToken, Int32 estimatedSize) at System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder`1.StateMachineBox`1.ExecutionContextCallback(Object s) at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder`1.StateMachineBox`1.MoveNext() at System.Net.Sockets.SocketAsyncEventArgs.<>c.<.cctor>b__174_0(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* nativeOverlapped) at System.Threading.PortableThreadPool.IOCompletionPoller.PollAndInlineCallbacks() --- End of stack trace from previous location --- --- End of inner exception stack trace --- at System.Net.Security.SslStream.EnsureFullTlsFrameAsync[TIOAdapter](CancellationToken cancellationToken, Int32 estimatedSize) at System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder`1.StateMachineBox`1.System.Threading.Tasks.Sources.IValueTaskSource<TResult>.GetResult(Int16 token) at System.Net.Security.SslStream.ReadAsyncInternal[TIOAdapter](Memory`1 buffer, CancellationToken cancellationToken) at System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder`1.StateMachineBox`1.System.Threading.Tasks.Sources.IValueTaskSource<TResult>.GetResult(Int16 token) at Npgsql.Internal.NpgsqlReadBuffer.<Ensure>g__EnsureLong|55_0(NpgsqlReadBuffer buffer, Int32 count, Boolean async, Boolean readingNotifications) at Npgsql.Internal.NpgsqlReadBuffer.<Ensure>g__EnsureLong|55_0(NpgsqlReadBuffer buffer, Int32 count, Boolean async, Boolean readingNotifications) at System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder`1.StateMachineBox`1.System.Threading.Tasks.Sources.IValueTaskSource.GetResult(Int16 token) at Npgsql.Internal.NpgsqlConnector.ReadMessageLong(Boolean async, DataRowLoadingMode dataRowLoadingMode, Boolean readingNotifications, Boolean isReadingPrependedMessage) at System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder`1.StateMachineBox`1.System.Threading.Tasks.Sources.IValueTaskSource<TResult>.GetResult(Int16 token) at Npgsql.Internal.NpgsqlConnector.Authenticate(String username, NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken) at Npgsql.Internal.NpgsqlConnector.<Open>g__OpenCore|214_1(NpgsqlConnector conn, SslMode sslMode, NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken) at Npgsql.Internal.NpgsqlConnector.Open(NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken) at Npgsql.UnpooledDataSource.Get(NpgsqlConnection conn, NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken) at Npgsql.NpgsqlConnection.<Open>g__OpenAsync|42_0(Boolean async, CancellationToken cancellationToken) at Npgsql.NpgsqlDataSource.OpenConnectionAsync(CancellationToken cancellationToken) at Npgsql.NpgsqlDataSource.OpenConnectionAsync(CancellationToken cancellationToken)using Npgsql; const string connString = "Host=localhost; Database=database; User ID=postgres; Password=password; Pooling=false"; var dataSource = NpgsqlDataSource.Create(connString); var tasks = new List<Task>(); for (var i = 0; i < 50; i++) { tasks.Add(Task.Run(async () => { while (true) { try { await using var connection = await dataSource.OpenConnectionAsync(); } catch (Exception ex) { Console.WriteLine(ex); } } })); } await Task.WhenAll(tasks);
Reacted by Nino Floris- added a commit that references this issue
on Nov 5, 2025 - added 2 commits that reference this issue
on Nov 5, 2025

My project is .NET Framework 4.8 and end up in
Exception while reading from streamwith inner exceptionVon der Übertragungsverbindung können keine Daten gelesen werden: Eine vorhandene Verbindung wurde vom Remotehost geschlossen.My test code
pg_hba.conf of windows postgres 15.7 server:
postgresql.conf requires ssl on:
it is als reproduceable without:
ssl_cert_file,ssl_key_file,ssl_ca_file, then it will end up with a proper error messageclient certificates can only be checked if a root certificate store is availablefor .NET 8. .NET Framework 4.8 fails again.Fun Fact:
If I build npgsql 8.0.8 in debug it works, if I build release it fails with above error.