2026년 07월 19일 | DBMS Error 가이드
이 글에서 다루는 내용
57P01 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
57P01 admin shutdown 는?
PostgreSQL 에러 코드 57P01 admin_shutdown은 데이터베이스 관리자(DBA)가 PostgreSQL 서버를 의도적으로 종료하거나 재시작하는 과정에서 클라이언트 연결이 강제로 끊길 때 발생하는 에러입니다. 주로 pg_ctl stop, systemctl stop postgresql, 또는 SELECT pg_terminate_backend() 같은 명령어를 통해 서버가 종료될 때 현재 진행 중인 세션에 이 에러가 전달됩니다. 일반적으로 서버 자체의 결함이 아닌 관리자의 명시적인 행동에 의해 발생하므로, 에러 원인 파악보다는 연결 복구 전략이 더 중요합니다.
주요 발생 원인
1. 관리자의 명시적 서버 종료 또는 재시작
운영 중 패치 적용, 설정 변경, 또는 정기 유지보수를 위해 DBA가 PostgreSQL 서버를 직접 종료할 때 가장 흔하게 발생합니다. pg_ctl stop -m fast 또는 pg_ctl stop -m immediate 명령어 실행 시 현재 세션에 연결된 모든 클라이언트에게 57P01 에러가 전달되며, 진행 중이던 트랜잭션은 롤백됩니다. 특히 immediate 모드는 체크포인트 없이 즉시 종료하므로 더욱 갑작스럽게 세션이 끊깁니다.
2. pg_terminate_backend() 함수를 통한 특정 세션 강제 종료
DBA가 특정 문제 세션(장시간 실행 쿼리, 잠금 대기 세션 등)을 수동으로 종료할 때 pg_terminate_backend() 함수를 사용하며, 이때 종료 대상 세션은 57P01 에러를 수신합니다. pg_cancel_backend()는 현재 쿼리만 취소하고 연결은 유지하지만(57014 query_canceled), pg_terminate_backend()는 연결 자체를 완전히 종료시킵니다. 모니터링 도구나 자동화 스크립트가 유휴 시간 초과 세션을 정리하는 과정에서도 동일하게 발생할 수 있습니다.
3. 연결 풀러(Connection Pooler) 또는 미들웨어의 세션 관리
PgBouncer, Pgpool-II 같은 연결 풀러가 재시작되거나 백엔드 연결을 재사용하는 과정에서 기존 세션이 강제 종료되어 57P01이 발생할 수 있습니다. 특히 PgBouncer를 RELOAD 또는 RESTART 할 때 기존에 체크아웃된 연결들이 끊기며, 애플리케이션 레이어에서 이를 적절히 처리하지 못하면 사용자에게 에러가 노출됩니다. 연결 풀러의 server_lifetime, server_idle_timeout 설정값에 따라 주기적으로 발생할 수도 있습니다.
해결 방법
원인 1: 서버 종료/재시작 시 연결 복구
서버가 재시작된 후 애플리케이션에서 자동으로 재연결하는 로직을 구현해야 합니다. 아래는 psycopg2를 사용한 Python 예제이며, PostgreSQL 측에서는 재시작 전 현재 연결 상태를 확인하는 쿼리를 활용할 수 있습니다.
-- 현재 활성 연결 수 및 상태 확인 (종료 전 사전 점검)
SELECT pid, usename, application_name, client_addr, state, query_start, state_change
FROM pg_stat_activity
WHERE state != 'idle'
AND pid != pg_backend_pid()
ORDER BY query_start;
-- 특정 데이터베이스의 모든 연결을 안전하게 종료 (서버 종료 전 준비 단계)
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE datname = 'your_database_name'
AND pid != pg_backend_pid();
-- 서버 재시작 후 연결 확인
SELECT version(), now() AS server_time, pg_postmaster_start_time() AS start_time;
원인 2: pg_terminate_backend() 남용 방지 및 대안 사용
무조건 세션을 종료하기 전에 pg_cancel_backend()로 현재 쿼리만 먼저 취소해 보고, 그래도 문제가 해결되지 않을 때만 pg_terminate_backend()를 사용하는 절차를 수립하세요.
-- 1단계: 장시간 실행 중인 쿼리 식별 (5분 이상)
SELECT pid, now() - pg_stat_activity.query_start AS duration,
query, state, usename, application_name
FROM pg_stat_activity
WHERE (now() - pg_stat_activity.query_start) > interval '5 minutes'
AND state = 'active';
-- 2단계: 먼저 쿼리 취소 시도 (연결 유지됨, 에러 코드: 57014)
SELECT pg_cancel_backend(pid)
FROM pg_stat_activity
WHERE (now() - query_start) > interval '5 minutes'
AND state = 'active';
-- 3단계: 그래도 안될 경우에만 세션 완전 종료 (에러 코드: 57P01 발생)
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE pid = <문제_세션_PID>;
-- 잠금 대기 세션 확인 후 종료
SELECT pg_terminate_backend(blocked_activity.pid)
FROM pg_stat_activity AS blocked_activity
JOIN pg_stat_activity AS blocking_activity
ON blocking_activity.pid = ANY(pg_blocking_pids(blocked_activity.pid))
WHERE blocked_activity.state = 'active';
원인 3: 연결 풀러 설정 최적화
PgBouncer 설정에서 타임아웃 값을 적절히 조정하고, 애플리케이션이 연결 끊김을 감지하여 재연결하도록 합니다.
-- PgBouncer 재시작 전 현재 풀 상태 확인 (psql로 PgBouncer 관리 콘솔 접속 후)
-- SHOW POOLS;
-- SHOW CLIENTS;
-- SHOW SERVERS;
-- PostgreSQL에서 연결 풀러가 사용하는 연결 확인
SELECT pid, usename, application_name, client_addr,
state, backend_start,
now() - backend_start AS connection_age
FROM pg_stat_activity
WHERE application_name LIKE '%pgbouncer%'
OR application_name LIKE '%pgpool%'
ORDER BY backend_start;
-- idle 상태의 오래된 연결 정리 (필요 시)
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE state = 'idle'
AND (now() - state_change) > interval '1 hour'
AND usename != 'replication';
예방 방법
1. 계획된 유지보수 시 graceful shutdown 절차 수립
서버를 종료할 때는 항상 smart 모드를 우선 사용하여 현재 활성 세션이 자연스럽게 완료된 후 종료되도록 하고, 유지보수 시간을 사전에 공지하는 절차를 마련하세요. 또한 애플리케이션 레벨에서 retry 로직과 connection_timeout 설정을 반드시 구현하여, 서버 재시작 후 자동으로 재연결될 수 있도록 해야 합니다. JDBC의 경우 connectTimeout, socketTimeout, loginTimeout 파라미터를, psycopg2의 경우 connect_timeout을, libpq 기반 드라이버는 connect_timeout 연결 파라미터를 적절히 설정하세요.
-- postgresql.conf에서 graceful shutdown을 위한 설정 확인
-- (pg_ctl stop -m smart 사용 권장)
-- 현재 세션 중 종료를 방해할 수 있는 장기 트랜잭션 모니터링
SELECT pid, usename, xact_start, now() - xact_start AS transaction_age,
state, query
FROM pg_stat_activity
WHERE xact_start IS NOT NULL
AND (now() - xact_start) > interval '10 minutes'
ORDER BY xact_start;
2. 자동화된 세션 모니터링 및 알림 체계 구축
pg_stat_activity를 주기적으로 모니터링하여 비정상적으로 장시간 실행되는 세션을 사전에 감지하고, Prometheus + pg_exporter 조합이나 Zabbix 같은 모니터링 툴을 활용해 알림 체계를 구축하세요. idle in transaction 상태가 일정 시간 이상 지속되는 세션은 잠금 문제를 유발하므로, idle_in_transaction_session_timeout 파라미터를 설정하여 자동으로 정리되도록 하면 수동으로 pg_terminate_backend()를 호출하는 빈도를 크게 줄일 수 있습니다.
-- postgresql.conf 또는 ALTER SYSTEM으로 설정
ALTER SYSTEM SET idle_in_transaction_session_timeout = '10min';
ALTER SYSTEM SET statement_timeout = '30min';
SELECT pg_reload_conf();
-- 설정 확인
SHOW idle_in_transaction_session_timeout;
SHOW statement_timeout;
관련 에러
57014query_canceled:pg_cancel_backend()또는statement_timeout초과 시 발생.57P01과 달리 연결은 유지됨.57P02crash_shutdown: PostgreSQL이 비정상적으로 충돌하여 종료될 때 발생.57P01은 관리자의 의도적 종료인 반면, 이 에러는 예기치 않은 서버 크래시를 의미함.57P03cannot_connect_now: 서버가 시작 중이거나 복구 중일 때 연결 시도 시 발생.57P01이후 재연결 시 일시적으로 마주칠 수 있음.08006connection_failure: 네트워크 레벨에서 연결이 끊길 때 발생하며,57P01과 혼동될 수 있으나 원인이 다름.08001sqlclient_unable_to_establish_sqlconnection: 클라이언트가 서버에 아예 연결하지 못할 때 발생. 서버 종료 후 재연결 시도 중 발생 가능.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.