PostgreSQL remaining connection slots 오류 해결: pg_stat_activity로 원인 진단

PostgreSQL 애플리케이션에서 remaining connection slots are reserved 오류가 나오면 일반 연결이 사용할 수 있는 슬롯이 거의 소진됐다는 뜻입니다. 단순히 max_connections가 작다고 결론 내리기보다, 어느 계정·애플리케이션이 연결을 차지하는지와 idle in transaction이 쌓였는지부터 확인해야 합니다. 이 글은 2026년 8월 10일 기준 PostgreSQL 18 공식 문서를 바탕으로 진단 순서를 정리했습니다.
빠른 결론
1.pg_stat_activity에서 상태·계정·앱별 연결 수를 집계합니다.
2. 풀 크기 합계, 반환 누락, 재연결 폭주, 장기 트랜잭션을 먼저 고칩니다.
3.max_connections증설과 세션 강제 종료는 영향과 권한을 확인한 뒤 검토합니다.
오류 메시지가 뜻하는 것
| 항목 | PostgreSQL 18 기준 의미 |
|---|---|
max_connections |
동시 연결 상한. 기본값은 보통 100이며 서버 시작 시 적용 |
superuser_reserved_connections |
슈퍼유저를 위해 남기는 최종 예약 슬롯. 기본값 3 |
reserved_connections |
pg_use_reserved_connections 권한 역할용 예약 슬롯. 기본값 0 |
pg_stat_activity |
현재 세션의 PID·계정·DB·앱·주소·상태·쿼리 시각 확인 |
오류 문구는 버전과 배포 환경에 따라 non-replication superuser connections 또는 roles with the SUPERUSER attribute처럼 보일 수 있습니다. 공통점은 일반 연결이 쓸 수 있는 슬롯이 한계에 도달했다는 점입니다.
pg_stat_activity로 진단하는 8단계
- 설정값과 현재 연결 수를 비교합니다.
SHOW max_connections; SHOW superuser_reserved_connections; SHOW reserved_connections; SELECT count(*) AS current_connections FROM pg_stat_activity; - 상태별 연결 수를 집계합니다.
SELECT coalesce(state, 'background') AS state, count(*) FROM pg_stat_activity GROUP BY state ORDER BY count(*) DESC;idle은 연결은 유지하지만 현재 쿼리를 실행하지 않는 상태이고,idle in transaction은 열린 트랜잭션 안에서 대기 중이므로 오래 지속되면 우선 점검 대상입니다. - 계정·DB·애플리케이션별 분포를 봅니다.
특정 WAS 인스턴스나 배치 계정이 대부분을 차지하는지 확인합니다.SELECT usename, datname, application_name, client_addr, state, count(*) FROM pg_stat_activity GROUP BY usename, datname, application_name, client_addr, state ORDER BY count(*) DESC; - 오래 열린 세션을 찾습니다.
SELECT pid, usename, datname, application_name, client_addr, state, state_change, query_start, query FROM pg_stat_activity WHERE pid <> pg_backend_pid() ORDER BY state_change;state_change와query_start를 함께 보면 장기 idle 트랜잭션과 장기 쿼리를 구분하는 데 도움이 됩니다. - 커넥션 풀의 최대치 합계를 계산합니다. 서버가 여러 대라면 HikariCP 같은 풀의
maximumPoolSize × 인스턴스 수에 관리 도구·배치 연결까지 더하세요. 합계가 일반 슬롯보다 크면 트래픽 순간에 오류가 반복될 수 있습니다. 기본 JDBC 연결 구성은 JDBC DB연결셋팅 글도 참고하세요. - 반환 누락과 재연결 폭주를 확인합니다. 예외 경로에서 연결을 닫지 않는 코드, 너무 짧은 재시도 간격, 헬스체크가 새 연결을 계속 만드는 구조를 로그와 함께 확인합니다.
- 취소와 종료를 구분합니다. 장기 쿼리는 먼저
SELECT pg_cancel_backend(pid);로 현재 쿼리만 취소할 수 있습니다. 슬롯을 비워야 하고 영향이 확인된 세션에 한해SELECT pg_terminate_backend(pid);를 검토합니다. - 구조를 고친 뒤 설정 변경을 판단합니다. 실제 동시 작업량이 한도보다 크고 메모리 여유가 검증됐을 때만 풀 크기 조정, PgBouncer 같은 풀러,
max_connections변경을 계획합니다.
주의사항
max_connections는 서버 시작 시에만 적용됩니다. 값을 높이면 공유 메모리를 포함한 자원 할당도 증가하므로 숫자만 크게 올리지 마세요.pg_cancel_backend는 쿼리를 취소하지만 세션은 유지합니다.pg_terminate_backend는 세션을 종료하므로 진행 중인 트랜잭션이 롤백되고 애플리케이션 오류가 발생할 수 있습니다.- 다른 역할 세션을 종료하려면 역할 멤버십이나
pg_signal_backend권한 등이 필요하며, 슈퍼유저 백엔드는 슈퍼유저만 종료할 수 있습니다. - 운영 DB에서 일괄 종료 쿼리를 바로 실행하지 말고 PID·계정·앱·쿼리·트랜잭션 영향을 한 건씩 확인하세요.
해결되지 않을 때 추가 점검
pg_stat_activity의 다른 세션 정보가 제한적으로 보이면 통계 조회 권한과 관리 계정을 확인합니다.- 연결 거부와 함께 포트 바인딩 오류가 있다면 java.net.BindException 점검에서 별도 원인을 구분하세요.
- 같은 유형의 한도 오류를 비교하려면 MySQL Too many connections 1040 진단도 참고할 수 있습니다.
- 시간대별 전체 연결 수, active 비율, idle in transaction 지속 시간, 풀 대기 시간을 모니터링해 배포나 트래픽과의 상관관계를 찾습니다.
FAQ
Q1. max_connections를 바로 올리면 해결되나요?
일시적으로 여유가 생길 수 있지만 반환 누락이나 풀 합계 초과가 원인이면 다시 소진됩니다. 자원 사용과 재시작 영향도 있으므로 원인 진단이 먼저입니다.
Q2. idle 연결은 모두 종료해야 하나요?
아닙니다. 풀에 정상 보관된 idle 연결도 있습니다. 특히 idle in transaction의 지속 시간, 앱별 연결 수, 풀 정책을 함께 보고 비정상 세션을 구분하세요.
Q3. pg_cancel_backend와 pg_terminate_backend 차이는 무엇인가요?
전자는 현재 쿼리만 취소하고 연결은 남깁니다. 후자는 세션 자체를 끝내므로 슬롯은 비지만 트랜잭션 롤백과 애플리케이션 재연결 영향을 확인해야 합니다.
공식 출처
- PostgreSQL 18 Connections and Authentication
- PostgreSQL 18 Monitoring Database Activity
- PostgreSQL 18 System Administration Functions
PostgreSQL 버전·관리형 서비스에 따라 변경 가능한 설정과 권한이 다릅니다. 적용 전 공급자 문서와 운영 환경을 함께 확인하세요.