Npgsql.NpgsqlException (0x80004005): Failed to connect to 127.0.0.1:15469 with the inner SocketException (10061): No connection could be made because the target machine actively refused it. — nothing is listening on that host and port. The PostgreSQL server is not running, or it listens on a different port from the one in your connection string.

Check with docker ps -a (is the container up, and which port did it publish?) and netstat -ano | findstr :15469 (does anything listen there?). Then start the server or correct Port= in the connection string. Nothing in the code needs to change.

The error

Unhandled exception. Npgsql.NpgsqlException (0x80004005): Failed to connect to 127.0.0.1:15469
 ---> System.Net.Sockets.SocketException (10061): No connection could be made because the target machine actively refused it.
   at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ThrowException(SocketError error, CancellationToken cancellationToken)

Why it happens

Before Npgsql can send a password or a query it must open a TCP connection to Host and Port. "Actively refused" means the machine answered and said that no program accepts connections on that port, so this is not a password, database or SSL problem; those errors come later, from PostgreSQL itself. Npgsql wraps the socket error in an NpgsqlException that names the address it tried.

With Docker the usual cause is a stopped container. On Windows, Docker Desktop's com.docker.backend process owns the published port while the container runs; after docker stop the LISTENING line disappeared from netstat and the same app failed with the same exception, now naming port 15460. The other cause is a port mismatch: the connection string says one port, the container publishes another. Refusals are not instant on Windows: 2.1 seconds with Host=127.0.0.1 and 4.2 seconds with Host=localhost, which resolves to ::1 and 127.0.0.1; the message named only 127.0.0.1.

The fix

PS> docker ps -a --filter name=fix7-pg --format "{{.Names}}  {{.Status}}  {{.Ports}}"
fix7-pg  Exited (0) Less than a second ago
PS> docker start fix7-pg
fix7-pg
PS> docker ps -a --filter name=fix7-pg --format "{{.Names}}  {{.Status}}  {{.Ports}}"
fix7-pg  Up 4 seconds  127.0.0.1:15460->5432/tcp
PS> netstat -ano | findstr :15460
  TCP    127.0.0.1:15460        0.0.0.0:0              LISTENING       21276
  TCP    127.0.0.1:51722        127.0.0.1:15460        TIME_WAIT       0
PS> dotnet run --no-build -- refused-fix
PostgreSQL 18.4 (Debian 18.4-1.pgdg13+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 14.2.0-19) 14.2.0, 64-bit

The Ports column shows the host side first: 127.0.0.1:15460 is what goes in the connection string, 5432 is the port inside the container. A LISTENING line in netstat for your port means something accepts connections there, and its last column is the process id; no line means the refusal will repeat.

Once the port answers, make sure it is the server you meant. On a PC that also runs a native PostgreSQL on 5432, a connection string that still says 5432 reaches that server instead, and the error becomes a password failure, as shown in Part 4 of the Windows setup series.

How it was reproduced

A .NET 10 console app (SDK 10.0.403, Npgsql 10.0.3) opened a connection to Host=127.0.0.1;Port=15469, where netstat -ano | findstr :15469 printed nothing. A postgres:18 container (PostgreSQL 18.4) on Docker 29.9.2 under Windows 11 was published on 127.0.0.1:15460; stopping it reproduced the error for that port and starting it fixed it. The timings came from a Stopwatch around OpenAsync. The name fix7-pg and the ports are this test's own, and the container was removed afterwards.

Frequently asked

What does Npgsql Failed to connect actively refused it mean?
Nothing is listening on the host and port in the connection string. The PostgreSQL server or its container is stopped, or it listens on another port. It happens before authentication, so the password and database name are not the problem yet.
How do I check if PostgreSQL is listening on a port on Windows?
Run netstat -ano | findstr :5432 with your port. A LISTENING line means something accepts connections there, and the last column is the process id. For a Docker container the process is com.docker.backend, and docker ps shows the published port.
Why does Npgsql take seconds to report connection refused on Windows?
In the test a refused connection to 127.0.0.1 took 2.1 seconds to report, and with Host=localhost it took 4.2 seconds; localhost resolves to both ::1 and 127.0.0.1, and the time doubled. Both runs ended in the same 10061 refusal.

More decoded errors in the Fixes category. psql reports the same refusal in its own words: connection refused (0x0000274D/10061), is the server running.