You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
CloneWith and CreateAdminConnection should own newly created connections #1814
NpgsqlRelationalConnection.CloneWith returns an instance with _connectionOwned=false, since the NpgsqlConnection is externally-provided; this means that disposing the instance doesn't close/dispose the connection leading to potential leaks (e.g. #1812). Fixing this properly requires upstream changes.
When this is done, #1813 can be reverted (can remove the Close, Dispose should be enough).
The below is an AI-generated analysis and may contain inaccuracies.
Confirmed provider bug; the existing Bug classification is appropriate.NpgsqlRelationalConnection.CloneWith creates a new NpgsqlConnection, but registers it through the WithConnection(connection) overload, which defaults to non-owning. Disposing the relational wrapper therefore does not close or dispose that new connection, and there is no external owner responsible for it.
Cause and scope
The ownership omission is still present in the current main implementation. It is a C# EF provider issue, not a driver disposal bug.
The issue's original upstream prerequisite no longer applies: EF's RelationalOptionsExtension.WithConnection(connection, owned: true) now supports expressing this ownership directly. No change to EF's Close behavior is needed. Close balances a connection opened by EF, including a caller-owned connection; disposal ownership is a separate contract.
Correction after checking the rebased implementation: #3648 already replaced the cloned-connection path in NpgsqlDatabaseCreator.Exists with SELECT 1 on the context's existing connection. The #1813 workaround therefore no longer exists on current main. The remaining Close/CloseAsync calls balance opening that existing connection and must stay; they are not redundant disposal cleanup. CloneWith currently has no production callers within the provider. The confirmed internal API ownership defect should not be read as evidence that ordinary CanConnectAsync calls still reproduce the original leak in #1812.
Minimal reproduction
Against a locally running PostgreSQL server, obtain the provider's internal connection service and dispose a clone without separately closing it:
The existing non-owning implementation leaves the connection open. The expected result is Closed, with the underlying NpgsqlConnection also disposed.
Validation and next step
Reviewed the original implementation and manually exercised #3565 against a real PostgreSQL server, first with its original EF Core 10 preview / Npgsql 9.0.3 dependencies, then after a local rebase onto main with EF Core 11.0.0-rc.2.26504.105 / Npgsql 10.0.3. Its owned: true change correctly closes and disposes clones for connection-string, supplied-connection, and data-source configuration, in both synchronous and asynchronous paths. The caller's original connection and data source remain usable.
The focused NpgsqlRelationalConnectionTest suite also passes all 24 tests after rebasing, but those tests do not currently assert cloned-connection disposal. Add regression coverage for disposal ownership before considering this issue complete.
This is a longstanding defect documented by this issue and #1813, not a newly established regression. A last-known-good release was not identified.
The same ownership defect also affects NpgsqlRelationalConnection.CreateAdminConnection(), particularly when the context is configured with an NpgsqlDataSource. That path creates a new connection but registers it with the non-owning WithConnection(connection) overload. There is no external owner responsible for disposing the new connection.
This path is still unfixed in #3565: its admin-connection change adds owned: true only to the supplied-connection branch, not the data-source branch. The latter needs the same ownership flag.
Minimal reproduction against PostgreSQL:
usingMicrosoft.EntityFrameworkCore;usingMicrosoft.EntityFrameworkCore.Infrastructure;usingNpgsql;usingNpgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal;conststringcs="Host=localhost;Database=postgres";usingvardataSource=NpgsqlDataSource.Create(cs);usingvarcontext=newDbContext(newDbContextOptionsBuilder().UseNpgsql(dataSource).Options);varadmin=context.GetService<INpgsqlRelationalConnection>().CreateAdminConnection();varraw=admin.DbConnection;try{admin.Open();admin.Dispose();Console.WriteLine(raw.State);// Actual: Open. Expected: Closed.}finally{raw.Dispose();// Clean up the connection left open by the wrapper.}
I manually reproduced this against PostgreSQL with EF Core 11.0.0-rc.2.26504.105 / Npgsql 10.0.3, including the equivalent OpenAsync / DisposeAsync path. The admin connection has pooling disabled, so leaving it open leaks a physical database connection until some other cleanup occurs; repeated leaks can exhaust PostgreSQL's connection limit.
Scope qualification: this demonstrates a leak through the internal admin-connection API, not that every ordinary database-creation or migration call leaks. Callers which explicitly close the connection can mask the defect. Correction after checking current main: #3648 replaced the cloned-connection path in CanConnect / Exists entirely; its remaining close calls balance opening the context's existing connection, rather than implementing the old #1813 workaround. This is not evidence that the original health-check leak in #1812 still occurs.
Regression coverage should verify that disposing both clones and admin wrappers closes and disposes their new connections, in synchronous and asynchronous paths, without disposing the caller's original connection or data source.
changed the title [-]NpgsqlRelationalConnection.CloneWith should return instance owning the connection[/-][+]CloneWith and CreateAdminConnection should own newly created connections[/+]on Oct 20, 2026
Activity
roji commentedon Oct 20, 2026
AI Triage
The below is an AI-generated analysis and may contain inaccuracies.
Confirmed provider bug; the existing Bug classification is appropriate.
NpgsqlRelationalConnection.CloneWithcreates a newNpgsqlConnection, but registers it through theWithConnection(connection)overload, which defaults to non-owning. Disposing the relational wrapper therefore does not close or dispose that new connection, and there is no external owner responsible for it.Cause and scope
The ownership omission is still present in the current main implementation. It is a C# EF provider issue, not a driver disposal bug.
The issue's original upstream prerequisite no longer applies: EF's
RelationalOptionsExtension.WithConnection(connection, owned: true)now supports expressing this ownership directly. No change to EF'sClosebehavior is needed.Closebalances a connection opened by EF, including a caller-owned connection; disposal ownership is a separate contract.Correction after checking the rebased implementation: #3648 already replaced the cloned-connection path in
NpgsqlDatabaseCreator.ExistswithSELECT 1on the context's existing connection. The #1813 workaround therefore no longer exists on current main. The remainingClose/CloseAsynccalls balance opening that existing connection and must stay; they are not redundant disposal cleanup.CloneWithcurrently has no production callers within the provider. The confirmed internal API ownership defect should not be read as evidence that ordinaryCanConnectAsynccalls still reproduce the original leak in #1812.Minimal reproduction
Against a locally running PostgreSQL server, obtain the provider's internal connection service and dispose a clone without separately closing it:
The existing non-owning implementation leaves the connection open. The expected result is
Closed, with the underlyingNpgsqlConnectionalso disposed.Validation and next step
Reviewed the original implementation and manually exercised #3565 against a real PostgreSQL server, first with its original EF Core 10 preview / Npgsql 9.0.3 dependencies, then after a local rebase onto main with EF Core 11.0.0-rc.2.26504.105 / Npgsql 10.0.3. Its
owned: truechange correctly closes and disposes clones for connection-string, supplied-connection, and data-source configuration, in both synchronous and asynchronous paths. The caller's original connection and data source remain usable.The focused
NpgsqlRelationalConnectionTestsuite also passes all 24 tests after rebasing, but those tests do not currently assert cloned-connection disposal. Add regression coverage for disposal ownership before considering this issue complete.This is a longstanding defect documented by this issue and #1813, not a newly established regression. A last-known-good release was not identified.
Posted by copilot.
roji commentedon Oct 20, 2026
The same ownership defect also affects
NpgsqlRelationalConnection.CreateAdminConnection(), particularly when the context is configured with anNpgsqlDataSource. That path creates a new connection but registers it with the non-owningWithConnection(connection)overload. There is no external owner responsible for disposing the new connection.This path is still unfixed in #3565: its admin-connection change adds
owned: trueonly to the supplied-connection branch, not the data-source branch. The latter needs the same ownership flag.Minimal reproduction against PostgreSQL:
I manually reproduced this against PostgreSQL with EF Core 11.0.0-rc.2.26504.105 / Npgsql 10.0.3, including the equivalent
OpenAsync/DisposeAsyncpath. The admin connection has pooling disabled, so leaving it open leaks a physical database connection until some other cleanup occurs; repeated leaks can exhaust PostgreSQL's connection limit.Scope qualification: this demonstrates a leak through the internal admin-connection API, not that every ordinary database-creation or migration call leaks. Callers which explicitly close the connection can mask the defect. Correction after checking current main: #3648 replaced the cloned-connection path in
CanConnect/Existsentirely; its remaining close calls balance opening the context's existing connection, rather than implementing the old #1813 workaround. This is not evidence that the original health-check leak in #1812 still occurs.Regression coverage should verify that disposing both clones and admin wrappers closes and disposes their new connections, in synchronous and asynchronous paths, without disposing the caller's original connection or data source.
Posted by copilot.
[-]NpgsqlRelationalConnection.CloneWith should return instance owning the connection[/-][+]CloneWith and CreateAdminConnection should own newly created connections[/+]marcusber commentedon Oct 20, 2026
Thanks @roji !
[10.0] Own newly cloned connections (#4056)