Why the Connection is Refused
When Python throws a ConnectionRefusedError: [Errno 111], your script is essentially shouting into a void. It means your code successfully reached the target IP address, but the destination operating system sent back a sharp "No." No service was listening on that specific port to catch your request.
This is different from a timeout. In a timeout, your request gets lost or ignored. In a refusal, the rejection is active and immediate at the TCP level. While Linux uses Errno 111, Windows developers will see WinError 10061 for the exact same problem.
The Usual Suspects
In 90% of cases, this error boils down to one of these four scenarios:
- The Ghost Service: Your database, Redis instance, or web server isn't actually running.
- Port Mismatch: You're knocking on port
5432, but your database was moved to5433last week. - The Isolation Trap: The service is listening on
127.0.0.1, but you’re trying to connect from a different container or an external IP. - Active Blocking: A firewall like
ufworiptablesis explicitly dropping the packets.
Step-by-Step Fixes
1. Confirm the Service is Alive
Don't assume your background tasks are running. Start by checking the status of the target service directly on the server.
# Check a system-level service
sudo systemctl status redis-server
# Or for Dockerized environments
docker ps | grep my_database_container
If the service isn't active, restart it. If it keeps crashing, dig into the logs at /var/log/ to find the underlying failure.
2. Hunt for the Listening Port
A service might be "up" but not listening where you expect. Use the ss tool to see which processes are actually holding ports open.
# List all active TCP listeners
sudo ss -tulpn | grep LISTEN
Scan the output for your port (e.g., :6379 for Redis). If your Python code targets 8080 but ss shows the service on 8081, update your connection string immediately.
3. Break Out of Localhost (The 127.0.0.1 Issue)
This is the most frequent hurdle in modern microservices. If a service binds to 127.0.0.1, it will only talk to itself. It is deaf to any external requests.
Imagine your Python script is in a Docker container trying to reach Redis at localhost:6379. It will fail. Inside a container, "localhost" refers to that specific container's loopback, not your host machine or the Redis service.
The Fix: Configure your service to listen on 0.0.0.0 (all interfaces). For a custom Python socket server, update your bind call:
# Instead of restricting to the loopback:
# sock.bind(('127.0.0.1', 8080))
# Open it up to the network:
sock.bind(('0.0.0.0', 8080))
4. Check Database-Specific Permissions
Databases often have their own internal gatekeepers. Even if the OS allows the connection, the DB might refuse it based on configuration.
- PostgreSQL: Open
postgresql.confand ensurelisten_addressesis set to'*'. Then, checkpg_hba.conffor IP permissions. - Redis: Check
redis.conf. Ensureprotected-modeisnoif you're connecting across a network. - MySQL: Look for
bind-address = 127.0.0.1in yourmy.cnfand change it to0.0.0.0.
5. Audit Firewalls and Security Groups
If the service is running and listening on 0.0.0.0 but you still get Errno 111, a firewall is likely the culprit. On Linux, explicitly allow the port.
# Open port 8080 on Ubuntu/Debian
sudo ufw allow 8080/tcp
If you are deployed on AWS or GCP, double-check your Inbound Security Group Rules. Ensure your script's IP address (or VPC range) is permitted to access that specific port.
Testing the Path
Before you restart your Python app, use a dedicated network tool. This proves the path is clear without involving any Python logic.
# Use netcat to check the port
nc -vz 192.168.1.50 8080
A successful connection will return succeeded!. If it still says Connection refused, the problem is definitely in your server configuration or network, not your code.
Pro-Tips for Prevention
Networking across complex subnets or VPCs is notoriously tricky. When I'm building out a new cluster, I use an IP Subnet Calculator to map out CIDR blocks. This prevents IP overlaps and makes it much easier to write accurate firewall rules the first time.
Also, avoid hardcoding localhost. Use environment variables like DB_HOST. This allows your app to switch from localhost during dev to db.internal.network in production without a single code change.
Final Thoughts
Errno 111 is rarely a bug in your Python logic. It is a configuration mismatch. Always verify the service is running, ensure it's listening on the right interface (0.0.0.0), and use nc to verify the path is open before you start rewriting your Python scripts.

