Common PostgreSQL Errors and How to Fix Them
PostgreSQL is a robust database system, but like any complex software, you'll encounter errors during development and production. This guide covers the most common PostgreSQL errors, their causes, and how to resolve them.
Connection Errors
1. FATAL: password authentication failed for user
Error Message:
FATAL: password authentication failed for user "postgres"
Causes:
- Incorrect password
- Wrong authentication method in
pg_hba.conf - User doesn't exist or lacks permissions
Solutions:
# Reset password for user
sudo -u postgres psql
ALTER USER postgres PASSWORD 'newpassword';
# Check pg_hba.conf authentication method
# Location: /etc/postgresql/[version]/main/pg_hba.conf
# Change from 'md5' to 'trust' temporarily (development only!)
local all postgres trust
# Reload configuration
sudo systemctl reload postgresql
2. could not connect to server: Connection refused
Error Message:
psql: error: could not connect to server: Connection refused
Is the server running on host "localhost" and accepting TCP/IP connections on port 5432?
Causes:
- PostgreSQL service not running
- Listening on wrong interface
- Firewall blocking connections
- Wrong port number
Solutions:
# Check if PostgreSQL is running
sudo systemctl status postgresql
# Start PostgreSQL
sudo systemctl start postgresql
# Check listening addresses in postgresql.conf
listen_addresses = '*' # Listen on all interfaces
port = 5432
# Verify PostgreSQL is listening
sudo netstat -plnt | grep 5432
# Check firewall
sudo ufw allow 5432/tcp
3. FATAL: too many connections for role
Error Message:
FATAL: too many connections for role "appuser"
Causes:
- Connection pool exhausted
- Application not closing connections
max_connectionslimit reached
Solutions:
-- Check current connections
SELECT count(*) FROM pg_stat_activity WHERE usename = 'appuser';
-- View connection limit
SELECT rolconnlimit FROM pg_roles WHERE rolname = 'appuser';
-- Increase connection limit for user
ALTER ROLE appuser CONNECTION LIMIT 50;
-- Or increase global max_connections in postgresql.conf
max_connections = 200
-- Kill idle connections
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE state = 'idle'
AND state_change < current_timestamp - INTERVAL '10 minutes'
AND usename = 'appuser';
Query Errors
4. ERROR: column does not exist
Error Message:
ERROR: column "username" does not exist
LINE 1: SELECT username FROM users;
Causes:
- Column name misspelled
- Column doesn't exist in table
- Using unquoted identifier with uppercase letters (PostgreSQL lowercases them)
Solutions:
-- Check actual column names
\d users
-- If column has uppercase letters, use quotes
SELECT "UserName" FROM users;
-- Or use the actual (lowercased) column name
SELECT username FROM users;
-- Check if column exists in table
SELECT column_name, data_type
FROM information_schema.columns
WHERE table_name = 'users';
5. ERROR: syntax error at or near
Error Message:
ERROR: syntax error at or near "FROM"
LINE 2: FROM users
Causes:
- SQL syntax error
- Missing comma in column list
- Reserved keyword used without quotes
- PostgreSQL-specific syntax differences
Solutions:
-- Common mistake: missing comma
SELECT
id,
name -- Missing comma here
email
FROM users;
-- Correct version
SELECT
id,
name,
email
FROM users;
-- Reserved keywords need quotes
CREATE TABLE "user" (id SERIAL); -- "user" is reserved
-- Or use different name
CREATE TABLE users (id SERIAL);
6. ERROR: operator does not exist
Error Message:
ERROR: operator does not exist: integer = character varying
Causes:
- Type mismatch in comparison
- Implicit type conversion not available
- Wrong operator for data type
Solutions:
-- Explicit type casting
SELECT * FROM products WHERE id = '123'::integer;
-- Or
SELECT * FROM products WHERE id = CAST('123' AS integer);
-- Use correct type from the start
SELECT * FROM products WHERE id = 123;
-- For text concatenation, use || not +
SELECT first_name || ' ' || last_name FROM users;
7. ERROR: duplicate key value violates unique constraint
Error Message:
ERROR: duplicate key value violates unique constraint "users_email_key"
DETAIL: Key (email)=(user@example.com) already exists.
Causes:
- Attempting to insert duplicate value in unique column
- Race condition in concurrent inserts
- Missing ON CONFLICT clause
Solutions:
-- Use ON CONFLICT to handle duplicates
INSERT INTO users (email, name)
VALUES ('user@example.com', 'John Doe')
ON CONFLICT (email) DO NOTHING;
-- Or update on conflict
INSERT INTO users (email, name, updated_at)
VALUES ('user@example.com', 'John Doe', NOW())
ON CONFLICT (email)
DO UPDATE SET
name = EXCLUDED.name,
updated_at = EXCLUDED.updated_at;
-- Check for existing record first
INSERT INTO users (email, name)
SELECT 'user@example.com', 'John Doe'
WHERE NOT EXISTS (
SELECT 1 FROM users WHERE email = 'user@example.com'
);
8. ERROR: null value in column violates not-null constraint
Error Message:
ERROR: null value in column "email" violates not-null constraint
Causes:
- Inserting NULL into NOT NULL column
- Missing value in INSERT statement
- Application passing NULL value
Solutions:
-- Provide value for NOT NULL columns
INSERT INTO users (email, name)
VALUES ('user@example.com', 'John Doe');
-- Use DEFAULT value
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT NOW()
);
-- Use COALESCE to provide fallback
INSERT INTO users (email, name)
VALUES (COALESCE(:email, 'default@example.com'), :name);
Performance Errors
9. ERROR: out of memory
Error Message:
ERROR: out of memory
DETAIL: Failed on request of size 1024.
Causes:
- Query consuming too much memory
work_memtoo low for complex operations- Memory leak in connection
- Too many concurrent connections
Solutions:
-- Increase work_mem for session
SET work_mem = '256MB';
-- Or in postgresql.conf
work_mem = 64MB
-- Use LIMIT for large result sets
SELECT * FROM large_table LIMIT 1000;
-- Use cursor for large datasets
BEGIN;
DECLARE large_cursor CURSOR FOR SELECT * FROM large_table;
FETCH 100 FROM large_cursor;
-- Process results
CLOSE large_cursor;
COMMIT;
-- Check memory usage
SELECT
pid,
usename,
application_name,
state,
query,
pg_size_pretty(pg_total_relation_size(query)) as query_size
FROM pg_stat_activity
WHERE state = 'active';
10. ERROR: canceling statement due to statement timeout
Error Message:
ERROR: canceling statement due to statement timeout
Causes:
- Query taking too long
statement_timeoutset too low- Missing or inefficient indexes
- Large table scans
Solutions:
-- Increase timeout for session
SET statement_timeout = '60s';
-- Or disable for specific query
SET statement_timeout = 0;
SELECT * FROM large_table;
SET statement_timeout = '30s';
-- In postgresql.conf
statement_timeout = 60000 # milliseconds
-- Analyze slow query
EXPLAIN ANALYZE SELECT * FROM large_table WHERE status = 'active';
-- Add appropriate index
CREATE INDEX idx_status ON large_table(status);
11. ERROR: deadlock detected
Error Message:
ERROR: deadlock detected
DETAIL: Process 1234 waits for ShareLock on transaction 5678; blocked by process 5678.
Process 5678 waits for ShareLock on transaction 1234; blocked by process 1234.
Causes:
- Circular lock dependency
- Different transaction lock order
- Long-running transactions
Solutions:
-- Always lock tables in same order
BEGIN;
LOCK TABLE users IN SHARE MODE;
LOCK TABLE orders IN SHARE MODE;
-- Perform operations
COMMIT;
-- Use row-level locking explicitly
SELECT * FROM accounts WHERE id = 1 FOR UPDATE;
-- Keep transactions short
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT;
-- Monitor locks
SELECT
l.locktype,
l.relation::regclass,
l.mode,
l.granted,
a.query
FROM pg_locks l
JOIN pg_stat_activity a ON l.pid = a.pid;
Index and Constraint Errors
12. ERROR: there is no unique constraint matching given keys for referenced table
Error Message:
ERROR: there is no unique constraint matching given keys for referenced table "users"
Causes:
- Foreign key references non-unique column
- Missing primary key or unique constraint
- Column types don't match
Solutions:
-- Ensure referenced column has unique constraint
ALTER TABLE users ADD CONSTRAINT users_email_unique UNIQUE (email);
-- Then create foreign key
ALTER TABLE orders
ADD CONSTRAINT fk_orders_user_email
FOREIGN KEY (user_email) REFERENCES users(email);
-- Or use primary key
ALTER TABLE orders
ADD CONSTRAINT fk_orders_user_id
FOREIGN KEY (user_id) REFERENCES users(id);
13. ERROR: relation does not exist
Error Message:
ERROR: relation "users" does not exist
Causes:
- Table doesn't exist
- Wrong schema
- Case sensitivity with quoted identifiers
- Not connected to correct database
Solutions:
-- Check if table exists
\dt
-- Check all schemas
SELECT schemaname, tablename
FROM pg_tables
WHERE tablename = 'users';
-- Use schema-qualified name
SELECT * FROM public.users;
-- Create table if it doesn't exist
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
email VARCHAR(255) NOT NULL
);
-- Check current database
SELECT current_database();
-- List all databases
\l
Transaction Errors
14. ERROR: current transaction is aborted
Error Message:
ERROR: current transaction is aborted, commands ignored until end of transaction block
Causes:
- Previous error in transaction
- Transaction not rolled back after error
- Application not handling errors properly
Solutions:
-- Roll back the transaction
ROLLBACK;
-- Then start new transaction
BEGIN;
-- Your queries
COMMIT;
-- Use savepoints for partial rollback
BEGIN;
SAVEPOINT sp1;
INSERT INTO users (email) VALUES ('test@example.com');
-- If error occurs
ROLLBACK TO SAVEPOINT sp1;
-- Continue transaction
COMMIT;
-- In application code (Python example)
try:
cursor.execute("INSERT INTO users ...")
conn.commit()
except Exception as e:
conn.rollback()
raise
15. ERROR: prepared transaction with identifier does not exist
Error Message:
ERROR: prepared transaction with identifier "tx123" does not exist
Causes:
- Two-phase commit transaction already committed/rolled back
- Wrong transaction identifier
- Transaction timeout
Solutions:
-- List prepared transactions
SELECT * FROM pg_prepared_xacts;
-- Commit prepared transaction
COMMIT PREPARED 'tx123';
-- Or rollback
ROLLBACK PREPARED 'tx123';
-- Check max_prepared_transactions setting
SHOW max_prepared_transactions;
-- Increase if needed in postgresql.conf
max_prepared_transactions = 100
Permission Errors
16. ERROR: permission denied for table
Error Message:
ERROR: permission denied for table users
Causes:
- User lacks required privileges
- Wrong role assigned
- Row-level security policy blocking access
Solutions:
-- Grant table privileges
GRANT SELECT, INSERT, UPDATE, DELETE ON users TO appuser;
-- Grant all privileges
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO appuser;
-- Grant schema usage
GRANT USAGE ON SCHEMA public TO appuser;
-- Grant sequence privileges (for SERIAL columns)
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO appuser;
-- Check current privileges
\dp users
-- Check user roles
\du appuser
Data Type Errors
17. ERROR: invalid input syntax for type
Error Message:
ERROR: invalid input syntax for type integer: "abc"
Causes:
- Wrong data type provided
- Invalid format for data type
- Type conversion failure
Solutions:
-- Use proper data type
INSERT INTO products (price) VALUES (19.99); -- Not '19.99'
-- Handle date formats
INSERT INTO events (event_date)
VALUES ('2025-12-26'::date);
-- Use proper boolean values
UPDATE users SET active = TRUE; -- Not 'true' or 1
-- Validate data before insert
INSERT INTO products (price)
VALUES (
CASE
WHEN '19.99' ~ '^\d+\.?\d*$'
THEN '19.99'::numeric
ELSE 0
END
);
Monitoring and Prevention
Best Practices to Avoid Common Errors:
-- Enable logging for errors
log_min_messages = error
log_min_error_statement = error
-- Log slow queries
log_min_duration_statement = 1000 # Log queries > 1 second
-- Monitor connections
SELECT
count(*),
state,
usename
FROM pg_stat_activity
GROUP BY state, usename;
-- Check for table bloat
SELECT
schemaname,
tablename,
pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename)) AS size
FROM pg_tables
ORDER BY pg_total_relation_size(schemaname||'.'||tablename) DESC
LIMIT 10;
-- Analyze query performance regularly
ANALYZE VERBOSE;
-- Check for missing indexes
SELECT
schemaname,
tablename,
seq_scan,
seq_tup_read,
idx_scan,
seq_tup_read / seq_scan as avg_seq_tup_read
FROM pg_stat_user_tables
WHERE seq_scan > 0
ORDER BY seq_tup_read DESC
LIMIT 10;
Related Resources
Monitor your PostgreSQL database and catch errors before they impact users with Pulse. Get real-time alerts, query analysis, and performance insights.