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 use
  • Microsoft.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. 1.Find and kill the process using the port:
  2. 2.```bash
  3. 3.# Windows
  4. 4.netstat -ano | findstr :5000
  5. 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. 1.Configure a different port:
  2. 2.```json
  3. 3.// appsettings.json
  4. 4.{
  5. 5."Kestrel": {
  6. 6."Endpoints": {
  7. 7."Http": {
  8. 8."Url": "http://localhost:5001"
  9. 9.},
  10. 10."Https": {
  11. 11."Url": "https://localhost:5002"
  12. 12.}
  13. 13.}
  14. 14.}
  15. 15.}
  16. 16.`
bash
# Or via environment variable
export ASPNETCORE_URLS="http://localhost:5001;https://localhost:5002"
# Or via command line
dotnet run --urls "http://localhost:5001"
  1. 1.Configure Kestrel programmatically:
  2. 2.```csharp
  3. 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. 1.Handle Windows URL reservations:
  2. 2.```bash
  3. 3.# Check URL reservations
  4. 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. 1.Add graceful shutdown to prevent zombie processes:
  2. 2.```csharp
  3. 3.var builder = WebApplication.CreateBuilder(args);
  4. 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-secrets to 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