Skip to main content

How to Resolve Python "OSError: [Errno 98] Address already in use"

When developing network applications (like web servers, socket servers, or APIs) in Python, you might encounter the OSError: [Errno 98] Address already in use or the closely related socket.error: [Errno 98] Address already in use. This error signals that the network address (specifically, the combination of IP address and port number) your application is trying to bind to is currently unavailable on your system.

This guide explains the common causes of this error and provides practical solutions for resolving it in various scenarios.

Understanding the Error: Occupied Network Address

Network applications "listen" for incoming connections on a specific network interface (IP address) and port number. Binding is the process of reserving this address/port combination for exclusive use by your application. The "Address already in use" error means this reservation failed because:

  • Another application process is currently actively bound to and using that exact IP address and port.
  • A socket from a previous run of your application (or another application) that used the same address/port recently closed but is still lingering in the operating system's TIME_WAIT state, preventing immediate reuse.

Cause 1: Another Process is Using the Port

The most straightforward cause is that another program (maybe a previous instance of your own app that didn't shut down cleanly, a different web server, or another network service) is actively running and bound to the port you're trying to use.

Solution 1: Find and Stop the Conflicting Process

You need to identify the process occupying the port and terminate it if it's not supposed to be running or if it's a zombie process.

Finding the Process ID (PID) on Linux/macOS (lsof)

Open your terminal and use the lsof (list open files) command. Replace 8000 with the port number causing the error.

# Check which process uses TCP port 8000
lsof -i :8000
# Or if you get permission errors:
sudo lsof -i :8000

# Example Output:
# COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
# python3 12345 myuser 3u IPv4 0xabcdef0123456789 0t0 TCP *:8000 (LISTEN)

Look for the PID (Process ID) column in the output (e.g., 12345 in the example).

Finding the Process ID (PID) on Windows (netstat)

Open Command Prompt (cmd) or PowerShell and use netstat. Replace 8000 with your port number.

netstat -ano | findstr ":8000"

:: Example Output:
:: TCP 0.0.0.0:8000 0.0.0.0:0 LISTENING 9876

Look at the last column for the PID (e.g., 9876 in the example).

Stopping the Process (kill/Task Manager)

  • Linux/macOS: Use the kill command with the PID you found. The -9 flag forcefully terminates the process.
    kill -9 <PID>
    # Example: kill -9 12345
    # Use sudo if necessary: sudo kill -9 12345
  • Windows:
    • Open Task Manager (Ctrl+Shift+Esc).
    • Go to the Details tab (or Processes tab in older Windows versions).
    • Find the process with the matching PID.
    • Right-click the process and select "End task" or "End process".
    • Alternatively, use taskkill in Command Prompt (run as Administrator):
      taskkill /PID <PID> /F
      :: Example: taskkill /PID 9876 /F

After stopping the conflicting process, try running your Python application again.

Cause 2: Socket Stuck in TIME_WAIT State

When a TCP socket connection closes, the endpoint that initiated the close often enters a TIME_WAIT state for a short period (e.g., 30-120 seconds). This is part of the TCP protocol to ensure any lingering packets are handled correctly. During TIME_WAIT, the operating system typically prevents another socket from binding to the exact same address/port combination. If you stop and immediately restart your server, you might hit this state.

Solution 2: Allow Address Reuse (SO_REUSEADDR)

You can instruct the operating system to allow your new socket to bind even if an old socket on the same address/port is in TIME_WAIT. This is done via the SO_REUSEADDR socket option.

note

Important: This option must be set before calling bind().

Using socket.setsockopt() (Raw Sockets)

If you are working directly with Python's socket module:

import socket

HOST = socket.gethostname() # Or 'localhost', '0.0.0.0', etc.
PORT = 8000

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# ✅ Set SO_REUSEADDR option BEFORE binding
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

try:
print(f"Binding to {HOST}:{PORT}...")
sock.bind((HOST, PORT))
sock.listen(1)
print("Server is listening...")
# ... rest of your server logic (accept connections, etc.) ...

except OSError as e:
print(f"Binding failed: {e}")
finally:
print("Closing socket.")
sock.close()

Setting the third argument of setsockopt to 1 enables the SO_REUSEADDR option.

Using allow_reuse_address (socketserver/http.server)

If using higher-level modules like socketserver or http.server, they often provide a simpler attribute to control this:

import socketserver
import http.server

PORT = 8000
Handler = http.server.SimpleHTTPRequestHandler # Example handler

# Use a context manager for clean shutdown
with socketserver.TCPServer(("", PORT), Handler) as httpd:
# ✅ Set allow_reuse_address to True BEFORE serving
httpd.allow_reuse_address = True
print(f"Serving HTTP on port {PORT} (allowing address reuse)...")
try:
httpd.serve_forever()
except KeyboardInterrupt:
print("\nServer stopped.")

Setting allow_reuse_address = True effectively sets the SO_REUSEADDR option on the underlying socket for you.

Flask Development Server (use_reloader=False)

When running Flask in debug mode (debug=True), it often uses a reloader process that automatically restarts the server when code changes. This rapid restarting can frequently trigger the TIME_WAIT issue. While SO_REUSEADDR helps, disabling the reloader during specific debugging phases can also prevent the error.

from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello():
return 'Hello, World!'

if __name__ == '__main__':
# ✅ Setting use_reloader=False prevents auto-restarts causing TIME_WAIT issues
# Note: You lose the auto-reload feature when code changes.
app.run(host='0.0.0.0', port=5000, debug=True, use_reloader=False)

# For production, use a proper WSGI server (Gunicorn, uWSGI) which handle
# socket binding more robustly, usually using SO_REUSEADDR by default.
# Setting debug=False also typically disables the reloader.
# app.run(debug=False)

Solution 3: Use a Different Port or Host (Workaround)

As a temporary fix or for testing, you can simply change the PORT number your application tries to bind to (e.g., 8001 instead of 8000) or potentially the HOST IP address if applicable. This avoids the conflict but doesn't address the root cause if the original port should have been available.

HOST = 'localhost'
PORT = 8001 # Changed from 8000

# ... rest of socket/server setup ...
# sock.bind((HOST, PORT))
# ...

Conclusion

The OSError: [Errno 98] Address already in use means the network address/port your Python application wants to use is unavailable.

  • Check for existing processes: Use tools like lsof (Linux/macOS) or netstat (Windows) to find and, if necessary, terminate any other process using the port.
  • Handle TIME_WAIT: For servers you frequently restart during development, set the SO_REUSEADDR socket option before binding. Use socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) for raw sockets or the allow_reuse_address = True attribute for libraries like socketserver. For Flask development, consider use_reloader=False.
  • Workaround: Temporarily use a different port number if the specific port isn't critical.

Applying the SO_REUSEADDR option in your server code is often the most effective long-term solution for issues caused by rapid restarts during development.