Fix java.net.BindException: Address already in use When Starting a Java Server

beginnerโ˜• Java2026-05-03| Java 8+, Spring Boot, Tomcat, Jetty โ€” Linux, macOS, Windows

Error Message

java.net.BindException: Address already in use: bind
#java#networking#bindexception#server

The Error

You start your Java server. It dies immediately with:

Exception in thread "main" java.net.BindException: Address already in use: bind
    at sun.nio.ch.Net.bind0(Native Method)
    at sun.nio.ch.Net.bind(Net.java:461)
    at sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:223)
    at io.netty.channel.socket.nio.NioServerSocketChannel.doBind(NioServerSocketChannel.java:134)

Spring Boot surfaces this as a slightly friendlier banner:

***************************
APPLICATION FAILED TO START
***************************
Description:
Web server failed to start. Port 8080 was already in use.
Action:
Identify and stop the process that's listening on port 8080 or configure this application to listen on another port.

The port your server wants is taken. The OS enforces a strict one-owner rule: one process per port, no exceptions.

Root Cause

A few things commonly cause this:

  • A previous instance of your server didn't exit cleanly and is still running in the background โ€” this is the #1 culprit.
  • Something else grabbed the port first: another Tomcat, a second Spring Boot app, or even a database (PostgreSQL defaults to 5432, MySQL to 3306, Redis to 6379).
  • You're in Docker and the container's port mapping collides with something on the host.
  • The socket is in TIME_WAIT state. The previous process exited, but the kernel is holding the port for up to 60 seconds to catch any stray packets.

Fix It: Find and Kill the Process Using the Port

Linux / macOS

Start by seeing what's on port 8080:

# Using lsof
lsof -i :8080

# Using ss (faster on modern Linux)
ss -tlnp | grep 8080

# Using netstat
netstat -tulnp | grep 8080

You'll get something like:

COMMAND   PID   USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
java     12345  ubuntu  42u  IPv6  123456      0t0  TCP *:8080 (LISTEN)

PID 12345 is your culprit. Kill it:

kill -9 12345

Want a one-liner that skips the PID lookup entirely?

fuser -k 8080/tcp

Windows

netstat -ano | findstr :8080

Grab the PID from the last column, then force-kill it:

taskkill /PID 12345 /F

Or skip the two-step dance with PowerShell:

Get-Process -Id (Get-NetTCPConnection -LocalPort 8080).OwningProcess | Stop-Process -Force

Fix It: Change Your Server's Port

Can't or don't want to kill the other process? Move your app to a different port instead.

Spring Boot (application.properties)

server.port=8081

Spring Boot (application.yml)

server:
  port: 8081

Spring Boot (command line โ€” no config change needed)

java -jar myapp.jar --server.port=8081

Embedded Tomcat (programmatic)

Connector connector = new Connector();
connector.setPort(8081);
tomcat.getService().addConnector(connector);

Plain Java ServerSocket

// Pick a specific free port
ServerSocket serverSocket = new ServerSocket(8081);

// Or let the OS pick โ€” pass 0 and ask what you got
ServerSocket serverSocket = new ServerSocket(0);
int assignedPort = serverSocket.getLocalPort();
System.out.println("Server started on port: " + assignedPort);

Port 0 is underused. The OS picks something free, no conflicts possible.

Fix It: Enable SO_REUSEADDR

Port stuck in TIME_WAIT? SO_REUSEADDR is the fix. Set it before calling bind() and the socket skips the wait entirely:

ServerSocket serverSocket = new ServerSocket();
serverSocket.setReuseAddress(true);  // must be set BEFORE bind()
serverSocket.bind(new InetSocketAddress(8080));

Netty, Tomcat, and Jetty all set this flag automatically. You only need to wire it yourself if you're building a raw server from scratch.

Docker-Specific Fix

Running in Docker? The conflict might be on the host, not inside the container:

# See what containers are already mapped to port 8080
docker ps
lsof -i :8080

# Stop the conflicting container
docker stop <container_id>

# Or just remap to a different host port
docker run -p 8081:8080 myapp

That last command keeps your app listening on 8080 inside the container. The host just reaches it through 8081 instead.

Verify the Fix

Before restarting, confirm the port is actually clear:

# Linux/macOS
lsof -i :8080
# No output = port is free

# Windows
netstat -ano | findstr :8080
# No output = port is free

Start your server and look for the successful bind message โ€” something like Started Application in 2.4 seconds or Server started on port 8080. If it's there, you're done.

Prevention

  • Shut down properly: Use SIGTERM or Ctrl+C โ€” don't just close the terminal. Closing the terminal can orphan the JVM process, and that process keeps holding the port. Register a shutdown hook if your app doesn't have one.
  • Use port 0 in tests: Binding to a hardcoded port in integration tests is asking for trouble, especially in CI where multiple jobs run in parallel. Use @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) and let Spring pick a free one.
  • Pre-flight check in startup scripts: Fail fast before the JVM even starts:``` lsof -i :8080 && echo "Port in use!" && exit 1
  - **Subnet/network conflicts in microservices**: If you're running several services and seeing bind errors on specific IPs rather than ports, you may have overlapping address ranges. The [Subnet Calculator at ToolCraft](https://toolcraft.app/en/tools/developer/ip-subnet-calculator) can help you verify your network allocations โ€” runs entirely in the browser, nothing uploaded.

Related Error Notes