2026년 09월 23일 | DBMS Error 가이드
이 글에서 다루는 내용
57P05 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
57P05 idle session timeout 는?
PostgreSQL 에러 코드 57P05 (idle_in_transaction_session_timeout 혹은 idle session timeout)은 데이터베이스 세션이 아무런 활동 없이 설정된 제한 시간을 초과했을 때 서버가 해당 연결을 강제로 종료하면서 발생하는 에러입니다. PostgreSQL 14부터 도입된 idle_session_timeout 파라미터가 활성화된 환경에서 클라이언트가 쿼리를 전송하지 않은 채 오랫동안 연결만 유지하고 있을 경우 서버는 해당 세션을 종료하고 이 에러를 반환합니다. 이 에러는 커넥션 풀 관리가 미흡하거나, 애플리케이션이 연결을 반납하지 않고 점유하는 상황에서 빈번하게 발생하며, 운영 중인 서비스에 예기치 않은 장애를 초래할 수 있습니다.
주요 발생 원인
idle_session_timeout파라미터 설정으로 인한 세션 자동 종료
PostgreSQL 14 이상 버전에서는 idle_session_timeout GUC(Grand Unified Configuration) 파라미터를 통해 유휴 세션을 자동으로 종료할 수 있습니다. 이 값이 서버 혹은 역할(Role) 레벨에서 짧게 설정되어 있을 경우, 애플리케이션이 DB 연결을 잠시 사용하지 않는 순간에도 연결이 끊겨 57P05 에러가 발생합니다. 특히 배치 작업 사이 대기 시간이 길거나 트랜잭션 없이 연결을 장시간 유지하는 패턴에서 자주 나타납니다.
- 커넥션 풀(Connection Pool) 미사용 또는 잘못된 설정
애플리케이션이 커넥션 풀을 사용하지 않거나 PgBouncer, pgpool-II 같은 풀러의 server_idle_timeout이 PostgreSQL의 idle_session_timeout보다 길게 설정된 경우, 풀러가 이미 서버 측에서 종료된 연결을 재사용하려 할 때 에러가 발생합니다. 커넥션 풀이 죽은 연결(dead connection)을 감지하지 못하면 클라이언트는 유효하지 않은 커넥션으로 쿼리를 전송하게 되어 서비스 장애로 이어집니다.
- 장시간 유휴 상태의 트랜잭션 외부 세션 유지
일부 ORM(Object-Relational Mapping) 라이브러리나 레거시 코드에서는 데이터베이스 연결을 오픈한 후 오랜 시간 동안 쿼리를 실행하지 않는 경우가 있습니다. 이런 패턴은 max_connections 한계에 도달하게 하는 원인이 되기도 하며, DBA가 유휴 연결을 정리하기 위해 idle_session_timeout을 설정하면 해당 세션들이 일괄 종료되면서 57P05 에러가 대량으로 발생할 수 있습니다.
해결 방법
1. idle_session_timeout 설정 확인 및 조정
현재 설정값을 확인하고 상황에 맞게 조정합니다.
-- 현재 idle_session_timeout 값 확인
SHOW idle_session_timeout;
-- 세션 레벨에서 일시적으로 비활성화 (테스트용)
SET idle_session_timeout = 0;
-- 특정 역할(Role)에 대해 타임아웃 연장
ALTER ROLE app_user SET idle_session_timeout = '10min';
-- 데이터베이스 레벨에서 설정
ALTER DATABASE mydb SET idle_session_timeout = '5min';
-- postgresql.conf 또는 ALTER SYSTEM으로 전역 설정
ALTER SYSTEM SET idle_session_timeout = '3min';
SELECT pg_reload_conf();
2. 현재 유휴 세션 모니터링 및 정리
운영 중 유휴 세션 현황을 파악하고 필요 시 수동으로 종료합니다.
-- 현재 유휴 세션 목록 조회 (idle 상태 & 5분 이상 유휴)
SELECT
pid,
usename,
application_name,
client_addr,
state,
state_change,
NOW() - state_change AS idle_duration,
query
FROM pg_stat_activity
WHERE state = 'idle'
AND state_change < NOW() - INTERVAL '5 minutes'
ORDER BY idle_duration DESC;
-- 특정 유휴 세션 강제 종료 (쿼리 취소)
SELECT pg_cancel_backend(pid)
FROM pg_stat_activity
WHERE state = 'idle'
AND state_change < NOW() - INTERVAL '10 minutes'
AND usename != 'postgres'; -- 슈퍼유저 세션 제외
-- 세션 자체를 완전히 종료
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE state = 'idle'
AND state_change < NOW() - INTERVAL '10 minutes'
AND usename != 'postgres';
3. PgBouncer server_idle_timeout 정렬
PgBouncer를 사용하는 경우, server_idle_timeout을 PostgreSQL의 idle_session_timeout보다 짧게 설정하여 풀러가 먼저 연결을 정리하게 합니다.
-- PostgreSQL 측 설정 확인
SHOW idle_session_timeout;
-- pgbouncer.ini 예시 권장 설정
-- server_idle_timeout = 60 (PostgreSQL idle_session_timeout보다 짧게)
-- server_lifetime = 3600
-- server_connect_timeout = 15
-- 연결 상태 확인 (psql로 pgbouncer에 접속 후)
-- SHOW SERVERS;
-- SHOW CLIENTS;
-- 애플리케이션에서 연결 검증 쿼리 예시
-- connection_test_query (JDBC 등에서 설정)
SELECT 1;
4. 애플리케이션 레벨 연결 유지 (Keep-Alive)
애플리케이션에서 주기적으로 연결 상태를 확인하는 쿼리를 실행합니다.
-- 연결 유효성 검사용 경량 쿼리
SELECT 1;
-- 또는 pg_stat_activity에서 자기 자신의 세션 정보 조회
SELECT pid, now() AS check_time
FROM pg_stat_activity
WHERE pid = pg_backend_pid();
예방 방법
idle_session_timeout을 역할/데이터베이스 단위로 세분화하여 관리
모든 사용자에게 동일한 타임아웃을 적용하기보다는, 역할(Role)과 데이터베이스 특성에 맞춰 세분화된 정책을 적용하는 것이 Best Practice입니다. 배치 처리 전용 역할에는 타임아웃을 길게, 웹 애플리케이션용 역할에는 짧게 설정하고, 커넥션 풀러의 타임아웃 값이 항상 PostgreSQL 서버의 타임아웃보다 짧게 유지되도록 정기적으로 감사(Audit)합니다.
“`sql
— 배치 작업 역할에는 긴 타임아웃 허용
ALTER ROLE batch_user SET idle_session_timeout = ’30min’;
— 웹 API 연결용 역할에는 짧은 타임아웃
ALTER ROLE web_app_user SET idle_session_timeout = ‘2min’;
— 설정 확인
SELECT rolname, rolconfig
FROM pg_roles
WHERE rolconfig IS NOT NULL;
“`
- 모니터링 자동화 및 알림 체계 구축
pg_stat_activity를 주기적으로 폴링하는 모니터링 스크립트를 작성하거나, Prometheus + pg_exporter, Datadog, Zabbix 등을 활용하여 유휴 세션 수가 임계치를 초과할 경우 알림을 받도록 설정합니다. 특히 idle_session_timeout으로 종료된 세션은 PostgreSQL 로그(log_connections, log_disconnections 활성화)를 통해 추적할 수 있으므로 로그 모니터링 체계도 함께 구축하는 것이 중요합니다.
“`sql
— 모니터링용 유휴 세션 집계 쿼리
SELECT
usename,
application_name,
COUNT(*) AS idle_count,
MAX(NOW() – state_change) AS max_idle_time,
MIN(NOW() – state_change) AS min_idle_time
FROM pg_stat_activity
WHERE state = ‘idle’
GROUP BY usename, application_name
ORDER BY idle_count DESC;
“`
관련 에러
- 25P03 (
idle_in_transaction_session_timeout): 트랜잭션이 열린 상태(idle in transaction)에서 장시간 유휴 상태가 지속될 때 발생하는 에러로,idle_in_transaction_session_timeout파라미터로 제어됩니다. 57P05와 혼동하기 쉽지만, 트랜잭션 블록 내 유휴 여부가 핵심 차이입니다. - 57014 (
query_canceled):statement_timeout또는 사용자의 명시적 취소로 쿼리가 중단될 때 발생하며, 타임아웃 관련 에러 중 가장 빈번하게 접하는 에러 코드입니다. - 08006 (
connection_failure): 네트워크 또는 서버 측 문제로 연결이 끊어질 때 발생하며, 57P05로 인해 세션이 종료된 후 재연결 시도 실패 시 함께 나타날 수 있습니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.