Python Psycog2: How to Resolve "psycopg2 OperationalError" in Python
When connecting to a PostgreSQL database using Python's psycopg2 library, you may encounter psycopg2.OperationalError, a broad exception that indicates something went wrong with the database connection or operation. This error can be triggered by incorrect credentials, network problems, a stopped database server, or configuration issues. In this guide, we'll cover the most common causes of this error, show what each error message looks like, and provide clear solutions for each scenario.
What Is psycopg2.OperationalError?
psycopg2.OperationalError is an exception class in the psycopg2 library (Python's most popular PostgreSQL adapter) that covers a range of connection and operational failures. Unlike programming errors, operational errors are typically caused by external factors: wrong credentials, unreachable servers, or misconfigured databases.
The error usually includes a descriptive message that tells you exactly what went wrong. Learning to read these messages is the key to fixing the issue quickly.
Common Causes and Solutions
1. Incorrect Database Credentials
The most frequent cause is providing wrong values for the database name, username, password, host, or port.
❌ Wrong: Incorrect database name
import psycopg2
conn = psycopg2.connect(
dbname="my_databse", # Typo: should be "my_database"
user="postgres",
password="mypassword",
host="localhost",
port="5432"
)
Output:
psycopg2.OperationalError: FATAL: database "my_databse" does not exist
❌ Wrong: Incorrect password
conn = psycopg2.connect(
dbname="my_database",
user="postgres",
password="wrong_password",
host="localhost",
port="5432"
)
Output:
psycopg2.OperationalError: FATAL: password authentication failed for user "postgres"
✅ Correct: Use verified credentials
import psycopg2
try:
conn = psycopg2.connect(
dbname="my_database",
user="postgres",
password="correct_password",
host="localhost",
port="5432"
)
print("Connected successfully!")
conn.close()
except psycopg2.OperationalError as e:
print(f"Connection failed: {e}")
Output:
Connected successfully!
Test your credentials directly with PostgreSQL's command-line tool before debugging Python code:
psql -h localhost -p 5432 -U postgres -d my_database
If this fails, the issue is with your credentials or PostgreSQL configuration, not with psycopg2.
2. PostgreSQL Server Is Not Running
If the PostgreSQL service isn't running, psycopg2 can't establish a connection.
Error output
psycopg2.OperationalError: could not connect to server: Connection refused
Is the server running on host "localhost" (127.0.0.1) and accepting
TCP/IP connections on port 5432?
Fix: Start the PostgreSQL service
# Linux (systemd)
sudo systemctl start postgresql
sudo systemctl status postgresql
# macOS (Homebrew)
brew services start postgresql
# Windows
net start postgresql-x64-15 # Version number may vary
Verify the server is running:
pg_isready -h localhost -p 5432
Expected output
localhost:5432 - accepting connections
3. Wrong Host or Port
If your PostgreSQL server is running on a different host or port than what you've specified, the connection will fail.
Error output (wrong host)
psycopg2.OperationalError: could not translate host name "wrong-host" to address: Name or service not known
Error output (wrong port)
psycopg2.OperationalError: could not connect to server: Connection refused
Is the server running on host "localhost" (127.0.0.1) and accepting
TCP/IP connections on port 5433?
Fix: Find the correct host and port:
# Check which port PostgreSQL is listening on
sudo ss -tlnp | grep postgres
# Or check the PostgreSQL config file
cat /etc/postgresql/15/main/postgresql.conf | grep port
Then update your connection parameters:
conn = psycopg2.connect(
dbname="my_database",
user="postgres",
password="mypassword",
host="localhost", # Or the actual server IP
port="5432" # Match the actual port
)
4. PostgreSQL Not Accepting TCP/IP Connections
By default, some PostgreSQL installations only accept local Unix socket connections and reject TCP/IP connections.
Error output
psycopg2.OperationalError: could not connect to server: Connection refused
Fix: Configure PostgreSQL to accept TCP/IP connections
Step 1: Edit postgresql.conf to listen on all addresses:
# Find the config file
sudo -u postgres psql -c "SHOW config_file;"
# Edit it
sudo nano /etc/postgresql/15/main/postgresql.conf
Change:
#listen_addresses = 'localhost'
To:
listen_addresses = '*' # Or 'localhost' for local connections only
Step 2: Edit pg_hba.conf to allow password authentication:
sudo nano /etc/postgresql/15/main/pg_hba.conf
Add or modify:
# TYPE DATABASE USER ADDRESS METHOD
host all all 127.0.0.1/32 md5
host all all 0.0.0.0/0 md5 # For remote connections
Step 3: Restart PostgreSQL:
sudo systemctl restart postgresql
Allowing connections from 0.0.0.0/0 opens your database to all IP addresses. In production, restrict this to specific IP ranges and always use strong passwords or certificate-based authentication.
5. Database Does Not Exist
If you specify a database name that hasn't been created, you'll get an error.
Error output
psycopg2.OperationalError: FATAL: database "myapp_db" does not exist
Fix: Create the database
# Using psql
sudo -u postgres psql -c "CREATE DATABASE myapp_db;"
# Or interactively
sudo -u postgres createdb myapp_db
Then connect:
conn = psycopg2.connect(
dbname="myapp_db",
user="postgres",
password="mypassword",
host="localhost",
port="5432"
)
print("Connected!")
6. SSL Connection Required
Some PostgreSQL servers (especially cloud-hosted ones like AWS RDS, Heroku, or Supabase) require SSL connections.
Error output
psycopg2.OperationalError: FATAL: no pg_hba.conf entry for host "x.x.x.x", user "postgres", database "mydb", SSL off
Fix: Enable SSL in the connection
import psycopg2
conn = psycopg2.connect(
dbname="my_database",
user="postgres",
password="mypassword",
host="your-cloud-host.amazonaws.com",
port="5432",
sslmode="require" # Enable SSL
)
print("Connected with SSL!")
Common sslmode values:
| Mode | Description |
|---|---|
disable | No SSL |
allow | Try non-SSL first, then SSL |
prefer | Try SSL first, then non-SSL (default) |
require | Must use SSL (no certificate verification) |
verify-ca | Must use SSL with CA certificate verification |
verify-full | Must use SSL with full certificate verification |
7. Too Many Connections
PostgreSQL has a maximum connection limit (default is usually 100). Exceeding it causes an error.
Error output
psycopg2.OperationalError: FATAL: too many connections for role "postgres"
Fix: Close connections properly and use connection pooling:
import psycopg2
from psycopg2 import pool
# Create a connection pool instead of individual connections
connection_pool = pool.SimpleConnectionPool(
minconn=1,
maxconn=10,
dbname="my_database",
user="postgres",
password="mypassword",
host="localhost",
port="5432"
)
# Get a connection from the pool
conn = connection_pool.getconn()
try:
cursor = conn.cursor()
cursor.execute("SELECT version();")
print(cursor.fetchone())
cursor.close()
finally:
# Return the connection to the pool (don't close it)
connection_pool.putconn(conn)
# When completely done
connection_pool.closeall()
Always close connections when you're done. Use try/finally blocks or context managers to ensure connections aren't leaked:
conn = psycopg2.connect(...)
try:
# Do work
pass
finally:
conn.close()
Robust Connection Template
Here's a production-ready connection pattern with proper error handling:
import psycopg2
import sys
import os
def get_db_connection():
"""Establish a connection to PostgreSQL with error handling."""
try:
conn = psycopg2.connect(
dbname=os.environ.get("DB_NAME", "my_database"),
user=os.environ.get("DB_USER", "postgres"),
password=os.environ.get("DB_PASSWORD", ""),
host=os.environ.get("DB_HOST", "localhost"),
port=os.environ.get("DB_PORT", "5432"),
connect_timeout=5, # Timeout after 5 seconds
)
print("✅ Connected to PostgreSQL successfully.")
return conn
except psycopg2.OperationalError as e:
error_message = str(e).strip()
if "does not exist" in error_message:
print(f"❌ Database not found: {error_message}")
elif "password authentication failed" in error_message:
print(f"❌ Authentication failed: {error_message}")
elif "Connection refused" in error_message:
print("❌ Connection refused. Is PostgreSQL running?")
elif "could not translate host name" in error_message:
print(f"❌ Invalid host: {error_message}")
else:
print(f"❌ Connection error: {error_message}")
sys.exit(1)
# Usage
conn = get_db_connection()
try:
cursor = conn.cursor()
cursor.execute("SELECT version();")
print(f"PostgreSQL version: {cursor.fetchone()[0]}")
cursor.close()
finally:
conn.close()
print("Connection closed.")
Output (successful connection):
✅ Connected to PostgreSQL successfully.
PostgreSQL version: PostgreSQL 15.4 on x86_64-pc-linux-gnu...
Connection closed.
Diagnostic Checklist
When you encounter psycopg2.OperationalError, work through these checks:
| # | Check | Command |
|---|---|---|
| 1 | Read the full error message | It tells you exactly what's wrong |
| 2 | Is PostgreSQL running? | pg_isready -h localhost -p 5432 |
| 3 | Can you connect via psql? | psql -h localhost -U postgres -d mydb |
| 4 | Is the port correct? | ss -tlnp | grep postgres |
| 5 | Is TCP/IP enabled? | Check postgresql.conf → listen_addresses |
| 6 | Is authentication configured? | Check pg_hba.conf |
| 7 | Does the database exist? | psql -l to list databases |
| 8 | Is SSL required? | Add sslmode="require" to connection |
| 9 | Are connections exhausted? | Check with SELECT count(*) FROM pg_stat_activity; |
Conclusion
The psycopg2.OperationalError is a catch-all exception for connection and operational failures with PostgreSQL.
The error message itself is your best diagnostic tool: it tells you whether the problem is wrong credentials, a stopped server, a network issue, a missing database, or an SSL requirement.
Always start by reading the full error message, verify your credentials with psql directly, check that PostgreSQL is running and accepting connections, and use proper error handling with try/except blocks in your code.
For production applications, use connection pooling and environment variables for credentials to build robust, maintainable database connections.