PostgreSQL Error 57P04: database dropped
PostgreSQL error 57P04 (database dropped) occurs when a client's active connection is invalidated because the database it was connected to has been deleted using DROP DATABASE. This is a critical, non-recoverable connection error — once the database is gone, the existing session has nowhere to point, and PostgreSQL immediately terminates it with this error code. Understanding the root causes and prevention strategies is essential for any production DBA.
Top 3 Causes
1. Forced DROP DATABASE with Active Connections
Since PostgreSQL 13, the WITH (FORCE) option allows dropping a database even when active connections exist. This forcibly terminates all connected backends, triggering error 57P04 on each of those sessions.
-- Check active connections before dropping
SELECT pid, usename, application_name, state
FROM pg_stat_activity
WHERE datname = 'mydb';
-- Gracefully terminate connections first
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE datname = 'mydb'
AND pid <> pg_backend_pid();
-- Safe drop after clearing connections
DROP DATABASE mydb;
-- DANGEROUS: Force drop (triggers 57P04 on active sessions)
-- DROP DATABASE mydb WITH (FORCE);
2. Misconfigured Automation Scripts (CI/CD Pipelines)
Automated test environment scripts that accidentally target the wrong database — due to misconfigured environment variables like PGDATABASE or DATABASE_URL — are a surprisingly common cause in DevOps environments.
-- Always validate the current database before destructive operations
DO $$
BEGIN
IF current_database() NOT IN ('test_db', 'staging_db') THEN
RAISE EXCEPTION 'Refusing to drop database: %. Not a safe target!',
current_database();
END IF;
END;
$$;
-- Only proceed if the above passes
DROP DATABASE IF EXISTS test_db;
3. Stale Connections via Connection Poolers
Tools like PgBouncer or Pgpool-II cache connections. After a database is dropped, the pooler may still hold references to old connections and hand them back to application clients, who then receive 57P04 unexpectedly.
-- Temporarily restrict new connections before maintenance
ALTER DATABASE mydb CONNECTION LIMIT 0;
-- Verify no connections remain
SELECT count(*)
FROM pg_stat_activity
WHERE datname = 'mydb';
-- Restore after maintenance
ALTER DATABASE mydb CONNECTION LIMIT -1;
Quick Fix Solutions
If the database has already been dropped, the only recovery path is restoring from a backup:
-- Step 1: Recreate the database
CREATE DATABASE mydb OWNER app_user;
-- Step 2: Restore from pg_dump backup (run in terminal)
-- pg_restore -U postgres -d mydb /backups/mydb_latest.dump
-- Step 3: Verify restoration
\c mydb
SELECT count(*) FROM information_schema.tables
WHERE table_schema = 'public';
For connection pooler issues, reload or restart the pooler after the database situation is resolved:
-- In PgBouncer admin console (psql -p 6432 pgbouncer)
-- RECONNECT mydb;
-- RELOAD;
Prevention Tips
1. Restrict DROP DATABASE privileges strictly.
Never grant SUPERUSER or CREATEDB to application accounts. Only dedicated DBA roles should have the ability to drop databases, and even then, require a confirmation step in scripts.
-- Application role with no destructive database-level privileges
CREATE ROLE app_user LOGIN PASSWORD 'strongpassword';
GRANT CONNECT ON DATABASE mydb TO app_user;
-- app_user cannot DROP DATABASE — it's not the owner and lacks SUPERUSER
2. Automate backups and regularly test restores.
A backup that has never been tested is not a real backup. Schedule pg_dump or pg_basebackup jobs and run periodic restore drills to a sandbox environment to confirm recoverability.
-- Log backup events for audit and monitoring
CREATE TABLE dba_backup_log (
db_name TEXT NOT NULL,
backup_taken TIMESTAMPTZ DEFAULT now(),
restore_tested BOOLEAN DEFAULT FALSE,
notes TEXT
);
Related Error Codes
| Code | Name | Description |
|---|---|---|
| 57P01 | admin_shutdown | Session terminated by administrator via pg_terminate_backend()
|
| 57P02 | crash_shutdown | Connection lost due to server crash |
| 57P03 | cannot_connect_now | Server is starting up or in recovery mode |
| 3D000 | invalid_catalog_name | Attempted connection to a non-existent database (often follows 57P04 on reconnect) |
📖 Want a more detailed guide?
Check out the full in-depth version (Korean) on oraerror.com — includes detailed analysis, additional SQL examples, and prevention tips.
Top comments (0)