Runtimes Intermediate

NPM EADDRINUSE: Resolving ‘Address Already In Use’ Port Conflicts in WSL2 Ubuntu

Fix EADDRINUSE errors when running Node.js apps in WSL2 Ubuntu. Learn to identify and terminate rogue processes or resolve port conflicts between WSL2 and Windows.

👨‍💻
Senior Systems Architect • Verified in Staging Labs

Fix EADDRINUSE errors when running Node.js apps in WSL2 Ubuntu. Learn to identify and terminate rogue processes or resolve port conflicts between WSL2 and Windows.

When developing Node.js applications within a Windows Subsystem for Linux 2 (WSL2) Ubuntu environment, it's a common frustration to encounter the EADDRINUSE error. This error, signifying "address already in use," prevents your application from starting because the network port it's attempting to bind to is already occupied by another process. This guide provides a highly technical, accurate, and step-by-step approach to diagnosing and resolving EADDRINUSE errors, specifically addressing the unique challenges posed by the WSL2 integration with Windows.

Symptom & Error Signature

When you attempt to start your Node.js application, typically using npm start or directly via node app.js, you'll observe an error message in your terminal similar to the following:

> [email protected] start
> node server.js

(node:12345) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 error listeners added to [Server]. Use emitter.setMaxListeners() to increase limit
events.js:180
      throw er; // Unhandled 'error' event
      ^

Error: listen EADDRINUSE: address already in use 127.0.0.1:3000
    at Server.setupServerHandle [as _setupServerHandle] (net.js:1326:16)
    at Server.listen (net.js:1424:12)
    at Object.<anonymous> (/path/to/your/app/server.js:5:4)
    at Module._compile (internal/modules/cjs/loader.js:1072:14)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1101:10)
    at Module.load (internal/modules/cjs/loader.js:932:32)
    at Function.Module._load (internal/modules/cjs/loader.js:777:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/cjs/loader.js:176:12)
    at internal/main/run_main_module.js:17:47 {
  code: 'EADDRINUSE',
  errno: -98,
  syscall: 'listen',
  address: '127.0.0.1',
  port: 3000
}

The key lines are Error: listen EADDRINUSE: address already in use followed by the IP address and port number (e.g., 127.0.0.1:3000 or 0.0.0.0:8080). This explicitly tells you which port is causing the conflict.

Root Cause Analysis

The EADDRINUSE error occurs when a process attempts to bind a network socket to an IP address and port combination that is already in use by another active process. In the context of WSL2 and Node.js, several scenarios commonly lead to this:

  1. Lingering Node.js Process: This is the most frequent cause. A previous instance of your Node.js application, or another Node.js process, might not have shut down cleanly. This can happen after a crash, an ungraceful exit (e.g., closing the terminal without proper shutdown), or if a background process was initiated and forgotten. The process continues to hold the port.
  2. Another WSL2 Linux Process: A different application running within the same WSL2 Ubuntu distribution (or even another WSL distribution) might be actively listening on the desired port. This could be another developer's project, a database, or a proxy server.
  3. Windows Host Process Conflict: Due to WSL2's integrated networking model, ports opened within WSL2 are often accessible from the Windows host, and vice-versa. An application running directly on your Windows host machine (e.g., Docker Desktop, Skype, XAMPP, another development server, or even a built-in Windows service) might be occupying the same port your Node.js application is trying to use. This is a critical distinction for WSL2 troubleshooting.
  4. Improper Process Management: If you're using process managers like pm2 or systemd, an application might be configured to automatically restart or might not have been stopped correctly, leading to multiple instances or a single persistent instance holding the port.

Step-by-Step Resolution

Follow these steps to diagnose and resolve the EADDRINUSE error, starting with the most common scenarios.

1. Identify and Terminate the Conflicting Process within WSL2

The first step is to check if a process within your WSL2 Ubuntu environment is holding the port.

  1. Identify the Port: From the error message, note the port number (e.g., 3000, 8080).

  2. Find the Process: Open your WSL2 Ubuntu terminal and use lsof or netstat to identify the process ID (PID) listening on that port.

    • Using lsof (List Open Files): This is often the easiest and most direct method.

      sudo lsof -i :<PORT_NUMBER>
      # Example for port 3000:
      # sudo lsof -i :3000
      

      The output will show the PID of the process. For example:

      COMMAND  PID  USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
      node    12345 user   14u  IPv4 0xdeadbeef      0t0  TCP *:3000 (LISTEN)
      

      Here, 12345 is the PID.

    • Using netstat (Network Statistics): If lsof is not installed or available, netstat can also be used.

      sudo netstat -tulnp | grep :<PORT_NUMBER>
      # Example for port 3000:
      # sudo netstat -tulnp | grep :3000
      

      The output will look something like this:

      tcp        0      0 0.0.0.0:3000            0.0.0.0:*               LISTEN      12345/node
      

      Again, 12345 is the PID.

  3. Terminate the Process: Once you have the PID, use the kill command to terminate it.

    sudo kill -9 <PID>
    # Example:
    # sudo kill -9 12345
    

    Using kill -9 (SIGKILL) forces an immediate termination and should be used cautiously as it doesn't allow the process to perform cleanup operations. For less critical processes, you might try kill <PID> (SIGTERM) first, which requests a graceful shutdown, and wait a few seconds before resorting to kill -9.

After terminating the process, attempt to start your Node.js application again.

2. Identify and Terminate the Conflicting Process on the Windows Host

If Step 1 doesn't resolve the issue, the port might be in use by an application running directly on your Windows host machine.

  1. Open Windows Command Prompt or PowerShell (as Administrator): Search for "cmd" or "powershell", right-click, and select "Run as administrator".

  2. Identify the Process: Use the netstat command with the findstr filter to locate processes listening on the specific port.

    netstat -ano | findstr :<PORT_NUMBER>
    # Example for port 3000:
    # netstat -ano | findstr :3000
    

    The output will show something similar to this:

      TCP    0.0.0.0:3000           0.0.0.0:0              LISTENING       6789
    

    The last column (6789 in this example) is the PID of the Windows process using the port.

  3. Identify the Application: To determine which application corresponds to the PID, use tasklist.

    tasklist /fi "PID eq <PID>"
    # Example:
    # tasklist /fi "PID eq 6789"
    

    This will show the image name (executable) associated with that PID, for instance:

    Image Name                     PID Session Name        Session#    Mem Usage
    MyApp.exe                     6789 Console                    1     56,789 K
    

    Common culprits include node.exe, docker-proxy.exe (related to Docker Desktop), httpd.exe (Apache), mysqld.exe (MySQL), or other development tools.

  4. Terminate the Process: Once you've identified the application, you can terminate it.

    taskkill /PID <PID> /F
    # Example:
    # taskkill /PID 6789 /F
    

    The /F flag forcefully terminates the process.

    Be cautious when terminating Windows processes, especially if you're unsure of their purpose. Forcefully killing critical system processes can lead to instability or data loss. If it's a known development tool, terminating it is generally safe. If it's an unknown process, consider identifying it further or simply choosing an alternate port for your Node.js application (see Step 3).

After terminating the Windows process, return to your WSL2 terminal and try starting your Node.js application again.

3. Adjust Your Application's Port

If you consistently find that a port is occupied by an essential service (either in WSL2 or Windows) that you cannot or should not terminate, the simplest solution is to configure your Node.js application to use a different port.

  1. Modify Your Application Code: Locate where your Node.js application listens for connections (e.g., app.listen(3000, ...)) and change the port number. It's good practice to make the port configurable, for example, via an environment variable:

    // In your server.js or app.js
    const port = process.env.PORT || 3001; // Use PORT environment variable, or default to 3001
    app.listen(port, () => {
      console.log(`Server listening on port ${port}`);
    });
    
  2. Start with a New Port: You can then launch your application specifying the new port:

    PORT=3001 npm start
    # or if you don't use the PORT env var directly in your app
    # node server.js --port 3001
    

    Choose an uncommon port number above 1024 to avoid conflicts with well-known services.

4. Restart WSL2 (Last Resort)

If you've tried the above steps and are still encountering persistent EADDRINUSE errors, or if you can't identify the conflicting process, a complete shutdown and restart of the WSL2 environment can often resolve the issue by clearing all active processes and network bindings.

  1. Close all WSL2 terminal windows.

  2. Open Windows Command Prompt or PowerShell (as Administrator):

  3. Shut down all WSL2 distributions:

    wsl --shutdown
    

    This command will terminate all running WSL distributions and any services or applications running within them. Ensure you've saved any work before proceeding.

  4. Restart WSL2: Simply open your Ubuntu terminal again, or run wsl in Command Prompt, to restart your default distribution.

After WSL2 has restarted, attempt to start your Node.js application.

5. Ensure Proper Process Management (Prevention)

To prevent EADDRINUSE errors from recurring, especially in development and production environments, adopt robust process management practices.

  • Graceful Shutdowns: Configure your Node.js application to handle SIGINT (Ctrl+C) and SIGTERM signals gracefully, allowing it to close connections and release ports before exiting.

    process.on('SIGINT', () => {
      console.log('Received SIGINT. Shutting down gracefully.');
      server.close(() => {
        console.log('Server closed. Exiting.');
        process.exit(0);
      });
    });
    
  • Using pm2 for Node.js Applications: For long-running Node.js processes, pm2 is an excellent process manager that provides features like automatic restarts, logging, and graceful shutdown.

    # Install pm2 globally
    npm install -g pm2
    
    # Start your app with pm2
    pm2 start server.js --name "my-node-app"
    
    # Stop and delete all pm2 processes
    pm2 stop all
    pm2 delete all
    

    Using pm2 stop <app_name> or pm2 delete <app_name> ensures processes are properly terminated and ports released.

  • Using systemd for Production (in Ubuntu): For production deployments within your WSL2 Ubuntu distribution, systemd is the standard for managing services. A systemd service file ensures your Node.js application starts on boot, restarts on failure, and can be stopped/started cleanly.

    # Example: /etc/systemd/system/my-node-app.service
    [Unit]
    Description=My Node.js Application
    After=network.target
    
    [Service]
    User=your_wsl_username
    WorkingDirectory=/path/to/your/app
    ExecStart=/usr/bin/node /path/to/your/app/server.js
    Restart=always
    RestartSec=3
    StandardOutput=syslog
    StandardError=syslog
    SyslogIdentifier=my-node-app
    
    [Install]
    WantedBy=multi-user.target
    

    Reload systemd, enable, and start your service:

    sudo systemctl daemon-reload
    sudo systemctl enable my-node-app.service
    sudo systemctl start my-node-app.service
    sudo systemctl stop my-node-app.service # To stop cleanly
    

    This approach helps prevent lingering processes and manages port binding reliably.

By systematically working through these steps, you can effectively diagnose and resolve the NPM EADDRINUSE error, ensuring your Node.js applications run smoothly within your WSL2 Ubuntu environment.

👨‍💻

Johnathon Wheeler

Senior Systems Architect & DevOps Engineer • Austin, TX

Connect on LinkedIn →

Johnathon has over 16 years of hands-on experience designing, debugging, and scaling Linux web hosting stacks, container clusters, and high-availability database architectures. Every guide on ButItWorkedLocal is independently tested against Debian 12, Ubuntu 24.04/22.04 LTS, Rocky Linux, and Docker environments to guarantee reproducibility in production.

🛡️

Our Production Verification Guarantee

Encountering a bug not covered here or running a non-standard kernel configuration? Our solutions are continually refined against real production incidents. Submit an environment trace for our editorial team to replicate.