PostgreSQL 57P04 오류 원인과 해결 방법 완벽 가이드

57P04
2026년 07월 20일 | DBMS Error 가이드

이 글에서 다루는 내용

57P04 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.

57P04 database dropped 는?

PostgreSQL 에러 코드 57P04 (database dropped)는 클라이언트가 연결된 데이터베이스가 서버 측에서 강제로 삭제(DROP DATABASE)되었을 때 발생하는 에러입니다. 이 에러는 기존 연결이 살아있는 상태에서 다른 세션이 해당 데이터베이스를 삭제하면, 기존 세션이 더 이상 유효하지 않은 데이터베이스를 참조하게 되면서 발생합니다. 일반적으로 DBA나 자동화 스크립트가 실수로 운영 중인 데이터베이스를 삭제하거나, 테스트 환경에서 데이터베이스를 재생성하는 과정에서 자주 목격됩니다.


주요 발생 원인

  • 운영 중인 데이터베이스의 강제 삭제 (DROP DATABASE)

가장 흔한 원인입니다. 관리자가 DROP DATABASE 명령을 실행할 때, 해당 데이터베이스에 활성 연결이 남아 있으면 PostgreSQL은 기본적으로 에러를 발생시켜 삭제를 거부합니다. 그러나 PostgreSQL 13 이후 도입된 WITH (FORCE) 옵션을 사용하면 활성 연결을 강제로 종료하고 데이터베이스를 삭제할 수 있으며, 이 경우 기존 세션은 57P04 에러를 수신하게 됩니다.

“`sql

— PostgreSQL 13+ 에서 강제 삭제 (연결 중인 세션에 57P04 발생)

DROP DATABASE mydb WITH (FORCE);

“`

  • 자동화 스크립트 또는 CI/CD 파이프라인의 오작동

DevOps 환경에서 테스트 DB를 자동으로 생성·삭제하는 스크립트가 잘못된 환경 변수를 참조하거나 타겟 DB를 잘못 지정하여 운영 데이터베이스를 삭제하는 경우가 발생합니다. 특히 환경 변수(PGDATABASE, DATABASE_URL 등)가 개발/운영 환경 간에 혼용될 때 치명적인 결과를 초래할 수 있습니다.

“`sql

— 잘못된 예: 환경 변수 확인 없이 무조건 삭제하는 스크립트 패턴

— 아래처럼 반드시 조건 확인 후 실행해야 합니다

DO $$

BEGIN

IF current_database() = ‘test_db’ THEN

RAISE NOTICE ‘테스트 DB 확인 완료. 삭제 진행.’;

ELSE

RAISE EXCEPTION ‘운영 DB입니다! 삭제를 중단합니다: %’, current_database();

END IF;

END;

$$;

“`

  • 연결 풀러(Connection Pooler) 환경에서의 잔여 연결 문제

PgBouncer, Pgpool-II 같은 연결 풀러를 사용하는 환경에서는, 데이터베이스가 삭제된 이후에도 풀러가 기존 연결을 캐싱하고 있어 클라이언트에게 이미 무효화된 연결을 반환하는 경우가 있습니다. 이로 인해 애플리케이션 레이어에서 예상치 못한 57P04 에러가 발생하며, 풀러를 재시작하거나 연결을 강제로 회수하지 않으면 에러가 지속될 수 있습니다.


해결 방법

원인 1: 강제 삭제 이후 복구

데이터베이스가 삭제된 경우, 백업에서 복원하는 것이 유일한 해결책입니다. 평소에 pg_dump 또는 pg_basebackup으로 백업을 유지해야 합니다.

-- 1단계: 새 데이터베이스 생성
CREATE DATABASE mydb;

-- 2단계: pg_restore로 백업 복원 (터미널에서 실행)
-- pg_restore -U postgres -d mydb /backup/mydb_backup.dump

-- 3단계: 복원 후 소유자 및 권한 재설정
ALTER DATABASE mydb OWNER TO app_user;
GRANT ALL PRIVILEGES ON DATABASE mydb TO app_user;

원인 2: 삭제 전 활성 연결 확인 및 종료

데이터베이스를 삭제하기 전에 반드시 활성 연결을 확인하고 안전하게 종료해야 합니다.

-- 활성 연결 확인
SELECT pid, usename, application_name, client_addr, state, query_start
FROM pg_stat_activity
WHERE datname = 'mydb';

-- 특정 DB의 모든 연결 강제 종료 (자기 자신 제외)
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE datname = 'mydb'
  AND pid <> pg_backend_pid();

-- 연결 종료 확인 후 안전하게 삭제
DROP DATABASE mydb;

원인 3: 연결 풀러 재설정

PgBouncer를 사용하는 경우 무효화된 연결 풀을 재설정합니다.

-- PgBouncer 관리 콘솔에서 특정 DB 풀 재연결 명령
-- psql -p 6432 pgbouncer 로 관리 콘솔 접속 후:
-- RECONNECT mydb;
-- RELOAD;

-- PostgreSQL에서 연결 수 제한으로 임시 방어
ALTER DATABASE mydb CONNECTION LIMIT 0;
-- 작업 완료 후 원복
ALTER DATABASE mydb CONNECTION LIMIT -1;

예방 방법

  • 데이터베이스 삭제 전 자동화된 체크리스트 적용

운영 데이터베이스에 대한 DROP DATABASE 실행 전, 해당 데이터베이스의 이름이 화이트리스트(허용 목록)에 없으면 자동으로 차단되는 스크립트나 훅을 CI/CD 파이프라인에 통합하세요. 또한 PostgreSQL의 pg_hba.conf와 역할(Role) 기반 권한 관리를 통해 일반 애플리케이션 계정에는 DROP DATABASE 권한 자체를 부여하지 않는 것이 가장 근본적인 예방책입니다.

“`sql

— 애플리케이션 전용 역할에는 데이터베이스 삭제 권한 부여 금지

— SUPERUSER 또는 CREATEDB 권한 없이 역할 생성

CREATE ROLE app_user LOGIN PASSWORD ‘securepassword’;

GRANT CONNECT ON DATABASE mydb TO app_user;

— DROP DATABASE는 SUPERUSER 또는 DB 소유자만 가능하므로

— app_user를 절대 DB 소유자로 설정하지 않음

“`

  • 정기적인 백업과 복구 테스트 자동화

pg_dump 또는 pg_basebackup을 사용한 정기 백업을 cron 또는 pgAgent로 자동화하고, 백업본이 실제로 복원 가능한지 주기적으로 복구 테스트(Restore Drill)를 수행해야 합니다. 백업이 존재하더라도 복원 불가능한 상태라면 아무런 의미가 없으므로 반드시 복원 검증 단계를 포함해야 합니다.

“`sql

— 백업 현황 확인용 커스텀 테이블 예시 (DBA 모니터링 DB에 관리)

CREATE TABLE backup_log (

id SERIAL PRIMARY KEY,

db_name TEXT NOT NULL,

backup_time TIMESTAMPTZ DEFAULT now(),

backup_size_bytes BIGINT,

backup_path TEXT,

verified BOOLEAN DEFAULT FALSE

);

— 복원 테스트 완료 시 검증 상태 업데이트

UPDATE backup_log

SET verified = TRUE

WHERE db_name = ‘mydb’

AND backup_time = (

SELECT MAX(backup_time) FROM backup_log WHERE db_name = ‘mydb’

);

“`


관련 에러

  • 57P01 (admin_shutdown): 관리자가 pg_ctl stop 또는 SELECT pg_terminate_backend(pid)를 통해 세션을 강제 종료했을 때 발생합니다. 57P04와 유사하게 연결이 외부 요인에 의해 끊기는 상황이지만, 데이터베이스 자체가 삭제되는 것은 아닙니다.
  • 57P02 (crash_shutdown): PostgreSQL 서버가 비정상 종료(크래시)되어 연결이 끊겼을 때 발생하는 에러로, 서버 장애 시나리오에서 57P04와 함께 모니터링해야 할 중요한 에러입니다.
  • 57P03 (cannot_connect_now): 서버가 시작 중이거나 복구 중인 상태여서 연결 자체가 불가능할 때 발생하며, 데이터베이스 재생성 후 서비스 재시작 과정에서 나타날 수 있습니다.
  • 3D000 (invalid_catalog_name): 존재하지 않는 데이터베이스에 연결을 시도할 때 발생하는 에러로, 57P04 이후 재연결 시도 시 함께 발생할 수 있습니다.

DBMS 에러 코드 시리즈

주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.

본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.

댓글 남기기