Skip to main content

Fixed: "System.IO.IOException: Failed to bind to address http://127.0.0.1:5190: address already in use." in ASP.NET Core

· 7 min read
Jagdish Kumawat
Founder @ Dewiride

System.IO.IOException: Failed to bind to address http://127.0.0.1:5190: address already in use. The app is fine; the port isn't free. Something else, very often another copy of the same app, is already listening on it. Here's how I found what held the port, stopped it cleanly, and when to pick another port instead.

What I Was Doing​

A .NET 10 Web API listens on port 5190, set in its Properties/launchSettings.json. I had one copy running in the background, and started another in a new terminal:

Terminal
dotnet run --project src/Dewiride.Inventory.Api

What I Expected​

Now listening on: http://localhost:5190, as every time before.

What I Got​

Output (first lines)
Using launch settings from src/Dewiride.Inventory.Api/Properties/launchSettings.json...
Building...
fail: Microsoft.Extensions.Hosting.Internal.Host[11]
Hosting failed to start
System.IO.IOException: Failed to bind to address http://127.0.0.1:5190: address already in use.
---> Microsoft.AspNetCore.Connections.AddressInUseException: Address already in use
---> System.Net.Sockets.SocketException (48): Address already in use
at System.Net.Sockets.Socket.UpdateStatusAfterSocketErrorAndThrowException(SocketError error, Boolean disconnectOnFailure, String callerName)
at System.Net.Sockets.Socket.DoBind(EndPoint endPointSnapshot, SocketAddress socketAddress)
at System.Net.Sockets.Socket.Bind(EndPoint localEP)

A terminal where dotnet run fails with Hosting failed to start, System.IO.IOException: Failed to bind to address http://127.0.0.1:5190: address already in use, wrapping AddressInUseException and SocketException 48.

Three exceptions, one inside the other: the operating system's SocketException (48), ASP.NET Core's AddressInUseException, and the IOException that stopped the host.

What I Checked​

What the documentation says. The Kestrel endpoints page describes exactly this: "When localhost is specified, Kestrel attempts to bind to both IPv4 and IPv6 loopback interfaces. If the requested port is in use by another service on either loopback interface, Kestrel fails to start." The AddressInUseException reference calls it "An exception that is thrown when there the current address Kestrel is trying to bind to is in use."

What holds the port. On macOS and Linux, lsof lists open files and network sockets; these options show only programs listening on TCP port 5190:

Terminal
lsof -nP -iTCP:5190 -sTCP:LISTEN
Output
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
Dewiride. 61818 you 211u IPv4 0x409b311339e52a6 0t0 TCP 127.0.0.1:5190 (LISTEN)
Dewiride. 61818 you 212u IPv6 0x9c39fb3e1b200129 0t0 TCP [::1]:5190 (LISTEN)

A terminal where lsof -nP -iTCP:5190 -sTCP shows process 61818, Dewiride.Inventory.Api, listening on 127.0.0.1:5190 and [::1]:5190.

  • -iTCP:5190: network sockets on TCP port 5190. -sTCP:LISTEN: only listening ones. -n -P: show numbers instead of looking up names, which is faster.
  • COMMAND is cut to nine characters: Dewiride. is Dewiride.Inventory.Api, the first copy.
  • Two lines, one process: it holds the port on both the IPv4 and the IPv6 loopback address, as the docs describe for localhost.

On Windows, PowerShell's Get-NetTCPConnection does the same job. I ran this fix on macOS; this Windows command is from Microsoft's documentation and wasn't run here:

PowerShell (Windows)
Get-Process -Id (Get-NetTCPConnection -LocalPort 5190 -State Listen).OwningProcess

Why It Happens​

The first copy of the API was still running in the background, listening on port 5190 on both loopback addresses. The operating system gives a port to one listener at a time, so when the second copy asked for the same port, it was refused, and, as the Kestrel docs say, "Kestrel fails to start".

The Fix​

Stop the copy that's already running. If you can see its terminal, press Ctrl+C there. Mine was in the background, so I sent it the stop signal by its process ID:

Terminal
kill -TERM 61818

kill -TERM asks the process to shut down, the same signal a service manager sends; it doesn't force it. ASP.NET Core handles it like Ctrl+C. The first copy's own log showed its normal goodbye:

Output (the first copy's log, last line)
Application is shutting down...

And lsof -nP -iTCP:5190 -sTCP:LISTEN printed nothing any more: the port was free.

After the Fix​

Output (dotnet run --project src/Dewiride.Inventory.Api)
Using launch settings from src/Dewiride.Inventory.Api/Properties/launchSettings.json...
Building...
info: Microsoft.Hosting.Lifetime[14]
Now listening on: http://localhost:5190
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Development

A terminal where dotnet run now starts normally and reports Now listening on http://localhost:5190 and Application started.

When You Want Both Copies Running​

Then give the second one another port for that run, without changing any file:

Terminal
dotnet run --project src/Dewiride.Inventory.Api --urls http://localhost:5200

How to Run an ASP.NET Core App on a Fixed Port shows that run and the other ways to set the port.

Common Mistakes​

MistakeWhat happensDo this instead
Using kill -9 firstThe process can't shut down cleanlyCtrl+C in its terminal, or kill -TERM; force only if it ignores those
Changing the port in launchSettings.json to dodge the errorEvery .http file and note with the old port is now wrongFree the port, or use --urls for the extra copy
Leaving a debug session running in the editorIt holds the port while you start another copy in a terminalStop one before starting the other
Assuming the other process is your appIt may be another program on the same portRead the COMMAND column first

Troubleshooting​

SymptomLikely causeFix
Failed to bind to address http://127.0.0.1:5190: address already in useAnother process listens on that portFind it with lsof -nP -iTCP:5190 -sTCP:LISTEN and stop it
lsof shows your own appAn earlier copy is still running, in another terminal, in the background or in the editor's debuggerStop it with Ctrl+C in its terminal, or kill -TERM and its PID
lsof shows a different programThat program uses the same portRun your app on another port with --urls

FAQ​

Why does the message say 127.0.0.1 when the app is set to localhost?​

localhost means both loopback addresses. Kestrel tried IPv4, 127.0.0.1, first, found it taken, and reported that one.

Can a crashed app keep the port?​

When a process ends, the operating system releases its listening sockets. If the port still shows in lsof, the process is still running, perhaps in another terminal or under the debugger.

Conclusion​

"Failed to bind to address … address already in use" means another process is listening on the port your app wants. Find it with lsof -nP -iTCP:<port> -sTCP:LISTEN on macOS and Linux, or Get-NetTCPConnection on Windows, and stop it the gentle way: Ctrl+C in its terminal or kill -TERM <pid>. If you need both copies, start the second with --urls on another port.

Additional Resources​

Stay Updated

Subscribe to our newsletter for the latest tutorials, tech insights, and developer news.

By subscribing, you agree to our privacy policy. Unsubscribe at any time.