2026년 09월 19일 | DBMS Error 가이드
이 글에서 다루는 내용
53300 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
53300 too many connections 는?
PostgreSQL 에러 코드 53300, too many connections는 데이터베이스 서버에 허용된 최대 클라이언트 연결 수를 초과했을 때 발생하는 에러입니다. PostgreSQL은 postgresql.conf의 max_connections 파라미터로 동시 접속 가능한 클라이언트 수를 제한하며, 이 한도를 초과하는 새로운 연결 요청은 즉시 거부됩니다. 웹 애플리케이션의 트래픽이 급증하거나, 커넥션 풀 설정이 잘못되어 있거나, 장시간 유지되는 유휴 연결(idle connection)이 누적될 때 주로 발생합니다.
주요 발생 원인
1. max_connections 설정값 초과 및 커넥션 풀 미사용
가장 흔한 원인으로, 애플리케이션이 커넥션 풀(PgBouncer, HikariCP 등)을 사용하지 않고 요청마다 새 연결을 직접 생성하는 패턴에서 발생합니다. PostgreSQL의 기본 max_connections 값은 100이며, 각 연결은 약 5~10MB의 메모리를 소비하므로 무작정 값을 올리는 것도 메모리 부족 문제로 이어질 수 있습니다. 트래픽이 급증하는 순간 연결 요청이 폭발적으로 늘어나 순식간에 한도를 초과합니다.
2. 유휴 연결(Idle Connection) 누적
애플리케이션이 연결을 맺은 후 사용하지 않으면서 반환하지 않는 경우, 유휴 상태의 연결이 계속 쌓여 가용 슬롯을 모두 소진합니다. 특히 커넥션 풀의 idle timeout 설정이 지나치게 길거나 아예 없는 경우, 오래된 유휴 연결이 서버의 연결 슬롯을 점유하며 실질적인 처리를 방해합니다. pg_stat_activity 뷰를 조회하면 state = 'idle'인 세션이 비정상적으로 많은 것을 확인할 수 있습니다.
3. 장시간 실행되는 트랜잭션(Long-running Transaction)
트랜잭션이 완료되지 않고 오랫동안 열려 있으면 해당 연결이 계속 점유됩니다. ORM이나 애플리케이션 코드의 버그로 인해 BEGIN 이후 COMMIT 또는 ROLLBACK이 호출되지 않아 연결이 반환되지 않는 경우도 매우 흔합니다. 이러한 연결들은 pg_stat_activity에서 state = 'idle in transaction'으로 표시되며, 다른 쿼리의 락(lock)을 유발할 수도 있어 이중으로 위험합니다.
해결 방법
현재 연결 상태 즉시 확인
에러 발생 시 가장 먼저 현재 연결 현황을 파악해야 합니다.
-- 현재 연결 수와 최대 연결 수 확인
SELECT
COUNT(*) AS current_connections,
(SELECT setting::int FROM pg_settings WHERE name = 'max_connections') AS max_connections,
(SELECT setting::int FROM pg_settings WHERE name = 'max_connections') - COUNT(*) AS remaining_slots
FROM pg_stat_activity;
-- 상태별, 데이터베이스별 연결 현황 상세 조회
SELECT
datname,
state,
COUNT(*) AS connection_count,
MAX(now() - state_change) AS max_duration
FROM pg_stat_activity
WHERE pid <> pg_backend_pid()
GROUP BY datname, state
ORDER BY connection_count DESC;
유휴 연결 강제 종료
즉각적인 해소가 필요할 경우 유휴 연결을 강제로 종료합니다.
-- 5분 이상 유휴 상태인 연결 강제 종료 (superuser 권한 필요)
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE state = 'idle'
AND state_change < now() - INTERVAL '5 minutes'
AND pid <> pg_backend_pid();
-- 'idle in transaction' 상태로 10분 이상 유지된 연결 종료
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE state = 'idle in transaction'
AND state_change < now() - INTERVAL '10 minutes'
AND pid <> pg_backend_pid();
max_connections 값 조정 (임시 해결책)
근본적인 해결책은 아니지만, 즉각적인 임시 조치로 max_connections 값을 늘릴 수 있습니다. 단, 서버 재시작이 필요하며 메모리 용량을 반드시 고려해야 합니다.
-- 현재 max_connections 확인
SHOW max_connections;
-- postgresql.conf 파일에서 수정 후 재시작 필요
-- max_connections = 200 (기본값: 100)
-- 재시작 없이 적용 가능한 파라미터 확인
SELECT name, setting, context
FROM pg_settings
WHERE name IN ('max_connections', 'superuser_reserved_connections');
> 주의: max_connections를 늘릴 경우 shared_buffers와 work_mem 등의 메모리 파라미터도 함께 재검토해야 합니다. 연결당 메모리 소비를 고려하면 일반적으로 300~500 이상으로 설정하는 것은 권장하지 않습니다.
특정 사용자/데이터베이스별 연결 제한 설정
-- 특정 데이터베이스의 최대 연결 수 제한
ALTER DATABASE myapp_db CONNECTION LIMIT 80;
-- 특정 사용자의 최대 연결 수 제한
ALTER ROLE app_user CONNECTION LIMIT 50;
-- 슈퍼유저 전용 예약 연결 확인 (기본값: 3)
SHOW superuser_reserved_connections;
PgBouncer를 활용한 커넥션 풀링 (근본 해결책)
PgBouncer의 pgbouncer.ini 설정 예시입니다.
[databases]
myapp_db = host=127.0.0.1 port=5432 dbname=myapp_db
[pgbouncer]
listen_port = 6432
listen_addr = *
auth_type = md5
auth_file = /etc/pgbouncer/userlist.txt
pool_mode = transaction
max_client_conn = 1000
default_pool_size = 25
min_pool_size = 5
reserve_pool_size = 5
reserve_pool_timeout = 3
server_idle_timeout = 600
예방 방법
1. 커넥션 풀러(Connection Pooler) 도입 및 모니터링 자동화
PgBouncer 또는 애플리케이션 레벨의 HikariCP, c3p0 같은 커넥션 풀을 반드시 도입하여 직접 연결 수를 최소화해야 합니다. 아울러 아래 쿼리를 Prometheus, Grafana, Zabbix 등의 모니터링 도구와 연동하여 연결 수가 max_connections의 80%를 초과하면 즉시 알림을 받도록 설정하는 것이 중요합니다.
-- 모니터링용 연결 사용률 쿼리 (80% 초과 시 경고)
SELECT
ROUND(COUNT(*) * 100.0 /
(SELECT setting::int FROM pg_settings WHERE name = 'max_connections'), 2) AS usage_pct
FROM pg_stat_activity
HAVING ROUND(COUNT(*) * 100.0 /
(SELECT setting::int FROM pg_settings WHERE name = 'max_connections'), 2) > 80;
2. idle_in_transaction_session_timeout 및 statement_timeout 설정
장시간 유지되는 유휴 트랜잭션 연결을 자동으로 종료하도록 타임아웃 파라미터를 설정합니다. 이는 postgresql.conf에 전역으로 설정하거나 역할(Role) 단위로 적용할 수 있으며, 연결 슬롯 낭비를 사전에 방지하는 가장 효과적인 예방책 중 하나입니다.
-- postgresql.conf 또는 ALTER SYSTEM으로 전역 설정
ALTER SYSTEM SET idle_in_transaction_session_timeout = '10min';
ALTER SYSTEM SET statement_timeout = '30min';
-- 특정 역할에만 적용
ALTER ROLE app_user SET idle_in_transaction_session_timeout = '5min';
ALTER ROLE app_user SET statement_timeout = '15min';
-- 설정 즉시 반영 (재시작 불필요)
SELECT pg_reload_conf();
-- 적용 확인
SHOW idle_in_transaction_session_timeout;
관련 에러
- 53100
disk_full: 디스크 공간 부족으로 인한 리소스 부족 에러로, 53300과 마찬가지로insufficient_resources카테고리에 속합니다. - 53200
out_of_memory: 메모리 부족 에러로,max_connections를 과도하게 높게 설정했을 때 함께 발생할 수 있습니다. - 57P03
cannot_connect_now: 서버가 시작 중이거나 복구 중일 때 발생하며, 연결 불가 상황이라는 점에서 53300과 유사한 맥락입니다. - 08006
connection_failure: 네트워크 단절이나 서버 측 오류로 연결이 실패할 때 발생하며, 53300과 혼동되는 경우가 있습니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.