Introduction
When Kestrel starts, it binds to the configured URL and port. If another process already holds that port, Kestrel throws an IOException with "Address already in use" and the application fails to start. This commonly occurs after a previous instance did not shut down cleanly, when running multiple instances, or when another service occupies the default port.
Symptoms
System.IO.IOException: Failed to bind to address http://0.0.0.0:5000: address already in useMicrosoft.AspNetCore.Server.Kestrel.Core.AddressInUseException- Application exits immediately on
dotnet run - Works on one port but not another
- Docker container fails to start with port conflict
Example error:
``
Unhandled exception. System.IO.IOException:
Failed to bind to address http://0.0.0.0:5000: address already in use.
---> Microsoft.AspNetCore.Connections.AddressInUseException:
Only one usage of each socket address (protocol/network address/port) is normally permitted.
---> System.Net.Sockets.SocketException (10048):
Only one usage of each socket address is normally permitted.
Common Causes
- Previous application instance did not shut down cleanly (zombie process)
- Another application uses the same port (IIS Express, another dev server)
- Docker port conflict when multiple containers map the same host port
- URL reservation conflict on Windows (netsh http)
- Running multiple instances without different ports
Step-by-Step Fix
- 1.Find and kill the process using the port:
- 2.```bash
- 3.# Windows
- 4.netstat -ano | findstr :5000
- 5.taskkill /PID <PID> /F
# Linux/macOS lsof -i :5000 kill -9 <PID>
# PowerShell Get-NetTCPConnection -LocalPort 5000 | Select-Object OwningProcess Stop-Process -Id <PID> -Force ```
- 1.Configure a different port:
- 2.```json
- 3.// appsettings.json
- 4.{
- 5."Kestrel": {
- 6."Endpoints": {
- 7."Http": {
- 8."Url": "http://localhost:5001"
- 9.},
- 10."Https": {
- 11."Url": "https://localhost:5002"
- 12.}
- 13.}
- 14.}
- 15.}
- 16.
`
# Or via environment variable
export ASPNETCORE_URLS="http://localhost:5001;https://localhost:5002"
# Or via command line
dotnet run --urls "http://localhost:5001"- 1.Configure Kestrel programmatically:
- 2.```csharp
- 3.var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(options => { options.ListenLocalhost(5001); // HTTP options.ListenLocalhost(5002, listenOptions => { listenOptions.UseHttps(); // HTTPS }); });
var app = builder.Build(); app.Run(); ```
- 1.Handle Windows URL reservations:
- 2.```bash
- 3.# Check URL reservations
- 4.netsh http show urlacl
# Remove conflicting reservation netsh http delete urlacl url=http://+:5000/
# Or add a new one for your user netsh http add urlacl url=http://+:5001/ user=Everyone ```
- 1.Add graceful shutdown to prevent zombie processes:
- 2.```csharp
- 3.var builder = WebApplication.CreateBuilder(args);
- 4.var app = builder.Build();
// Configure shutdown timeout app.Lifetime.ApplicationStopping.Register(() => { Console.WriteLine("Application is shutting down..."); });
// Set shutdown timeout in Program.cs builder.WebHost.ConfigureKestrel(options => { options.Limits.KeepAliveTimeout = TimeSpan.FromSeconds(5); options.Limits.RequestHeadersTimeout = TimeSpan.FromSeconds(5); });
app.Run(); ```
Prevention
- Use
dotnet user-secretsto manage ports per developer - Add a startup script that checks and frees the port before starting
- Configure Docker Compose with unique port mappings per service
- Use dynamic port assignment in development:
ASPNETCORE_URLS=http://localhost:0 - Add health check endpoint to verify the correct instance is running
- Set up proper process supervision (systemd, Docker restart policies) to clean up zombies