← Back to DevBytes

Fix 'ConnectionRefusedError' in Python

Understanding ConnectionRefusedError in Python

When a Python program tries to connect to a remote service or local daemon and receives an abrupt rejection, you'll typically see ConnectionRefusedError in the traceback. This exception is a subclass of OSError (specifically ConnectionError) and indicates that the operating system of the target machine actively refused the connection attempt. Fixing it requires understanding the network stack, the lifecycle of sockets, and the specific context in which your code is running.

What Is ConnectionRefusedError?

ConnectionRefusedError is raised when a TCP connection request (a SYN packet) reaches the target host, but no process is listening on the specified port, or the listening process explicitly rejects the connection due to its backlog or configuration. In Python's socket and high‑level networking modules (like http.client, urllib, requests, or asynchronous frameworks), the underlying system call returns an error that Python translates into this built‑in exception.

The error number typically maps to errno.ECONNREFUSED (error code 111 on Linux). It's different from a timeout (TimeoutError) where no response arrives, and from ConnectionResetError where an established connection is forcibly closed by the peer.

Why It Matters

Ignoring or mishandling ConnectionRefusedError can lead to:

Understanding this error empowers you to write robust network code that can distinguish between transient unavailability (worth retrying) and permanent configuration mistakes (which should fail fast).

Common Scenarios and Root Causes

You'll encounter ConnectionRefusedError most often in these situations:

How to Fix It: Step‑by‑Step Guide

The fix depends on which side of the connection you control. Below are practical checks and code patterns for both client and server contexts.

1. Verify the Server is Running and Listening

Before modifying Python code, confirm the target process is actually listening. On Linux/macOS, use netstat or ss:

# Check if something listens on port 8080
$ ss -tlnp | grep 8080
# or
$ netstat -tlnp | grep 8080

If nothing appears, start the server. For example, a simple Python HTTP server:

# In one terminal – starts a server on port 8000
python -m http.server 8000 --bind 0.0.0.0

Now a Python client can connect successfully:

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
    s.connect(('127.0.0.1', 8000))
    print("Connected!")
except ConnectionRefusedError:
    print("Server not running or port closed")
finally:
    s.close()

2. Check Firewall and Network Rules

Even when a server is listening, a firewall can drop or reject packets. On the server machine, temporarily disable the firewall for testing (with caution) or add a rule:

# Linux iptables example to allow port 8000
$ sudo iptables -I INPUT -p tcp --dport 8000 -j ACCEPT

In cloud environments, verify security groups (AWS, GCP) allow inbound traffic on the desired port from the client's IP range. In Docker, ensure the -p flag maps the container port correctly:

# Run a container and map container port 5000 to host port 5000
docker run -p 5000:5000 myapp

3. Correct the Host and Port

A frequent mistake is using 'localhost' when the server binds only to the public IP, or using the wrong port. Make sure the client connects to the exact address the server listens on:

# Server binds to all interfaces (0.0.0.0) on port 9000
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('0.0.0.0', 9000))
server_socket.listen()

# Client must use the server's reachable IP, e.g., '192.168.1.10' or 'localhost' if on same machine
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect(('192.168.1.10', 9000))   # NOT '127.0.0.1' unless client is on the server machine

If the port is dynamic, consider a service discovery mechanism or pass it as an environment variable.

4. Handle the Error Gracefully with Retry Logic

Transient ConnectionRefusedError often occurs during container orchestration when a pod starts before its dependency. Implement a retry loop with exponential backoff:

import socket
import time
import sys

def connect_with_retry(host, port, max_retries=5, backoff=1):
    for attempt in range(1, max_retries + 1):
        try:
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.settimeout(2.0)   # fail fast on each attempt
            sock.connect((host, port))
            print(f"Connected on attempt {attempt}")
            return sock
        except ConnectionRefusedError:
            print(f"Attempt {attempt}: connection refused, retrying in {backoff}s")
            time.sleep(backoff)
            backoff *= 2   # exponential backoff
        finally:
            # sock not connected, close the failed socket
            pass
    raise ConnectionRefusedError(f"Could not connect to {host}:{port} after {max_retries} attempts")

try:
    sock = connect_with_retry('127.0.0.1', 8000)
    # use the connected socket...
    sock.close()
except ConnectionRefusedError as e:
    print("Permanent failure:", e)
    sys.exit(1)

5. Use a Context Manager or Timeout to Avoid Hanging

Sometimes the error is masked by a long wait. Always set socket timeouts so you get a quick rejection instead of an indefinite hang:

sock = socket.create_connection(('127.0.0.1', 8000), timeout=3)
# If server is not listening, ConnectionRefusedError is raised within 3 seconds

Higher‑level libraries like requests also accept a timeout parameter:

import requests

try:
    response = requests.get('http://localhost:8000', timeout=2)
    response.raise_for_status()
except requests.ConnectionError as e:
    # Under the hood, this often wraps a ConnectionRefusedError
    print("Connection failed:", e)

Best Practices to Avoid ConnectionRefusedError

Conclusion

ConnectionRefusedError is a clear signal: the target machine is reachable, but the specific port is not open for business. By systematically checking the server status, firewall rules, correct host/port values, and implementing resilient client-side retries, you can turn this common error into a manageable, temporary condition. Always combine these fixes with proper timeouts and robust error handling to build network applications that gracefully withstand real‑world startup races and intermittent failures.

🚀 Need a reliable AI agent for your project?

Deploy Hermes Agent in 10 minutes. Managed hosting, zero DevOps.

Get Started — $23.99/mo
← Back to all articles