Oracle ORA-12516 오류 원인과 해결 방법 완벽 가이드

ORA-12516
2026년 09월 11일 | DBMS Error 가이드

이 글에서 다루는 내용

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

ORA-12516 TNS: listener could not find available handler with matching protocol stack 는?

ORA-12516 에러는 Oracle 데이터베이스 리스너(Listener)가 클라이언트의 연결 요청을 처리할 수 있는 가용 핸들러(Handler)를 찾지 못할 때 발생합니다. 쉽게 말해, 데이터베이스 서버가 새로운 클라이언트 연결을 받아들일 여력이 없는 상태로, 보통 최대 프로세스 수나 세션 수가 한계에 도달했거나 리스너와 데이터베이스 인스턴스 간의 프로토콜 스택 불일치가 발생했을 때 나타납니다. 특히 트래픽이 급증하는 시간대나 애플리케이션의 커넥션 풀 설정이 부적절할 때 빈번하게 발생하며, 서비스 중단으로 이어질 수 있는 심각한 에러입니다.


주요 발생 원인

1. PROCESSES 및 SESSIONS 파라미터 한계 초과

가장 흔한 원인으로, 데이터베이스 초기화 파라미터인 PROCESSESSESSIONS의 최댓값이 실제 접속 수요를 감당하지 못할 때 발생합니다. Oracle에서 SESSIONS 파라미터는 통상 PROCESSES * 1.1 + 5 공식으로 자동 산출되며, PROCESSES 값이 낮게 설정되어 있으면 새로운 서버 프로세스를 생성하지 못해 리스너가 연결 요청을 거부하게 됩니다. 실제 운영 환경에서는 배치 작업, 대규모 이벤트, 비효율적인 커넥션 누수(Connection Leak) 등이 복합적으로 작용하여 이 한계를 초과하는 경우가 많습니다.

2. 커넥션 풀(Connection Pool) 미설정 또는 커넥션 누수(Connection Leak)

애플리케이션 레이어에서 커넥션을 사용 후 제대로 반환하지 않거나(커넥션 누수), 커넥션 풀의 최대 크기가 지나치게 크게 설정된 경우 데이터베이스 측의 세션이 비정상적으로 누적됩니다. 이 경우 실제로는 아무 작업도 하지 않는 유휴(Inactive) 세션들이 프로세스 슬롯을 점유하여 정상적인 새 연결이 불가능해지며, 특히 Java, Python, Node.js 기반 애플리케이션에서 자주 목격되는 패턴입니다. 장시간 운영되다가 서비스 점검 없이 갑자기 연결 불가 상태가 되는 경우 대부분 이 원인이 해당됩니다.

3. 리스너 설정 오류 또는 MTS(Multi-Threaded Server) 구성 문제

리스너의 listener.ora 또는 sqlnet.ora 설정이 클라이언트의 프로토콜 스택과 일치하지 않을 때도 ORA-12516이 발생합니다. 또한 MTS(현재는 Shared Server라고도 불림) 환경에서 DISPATCHERS 파라미터가 부족하게 설정되어 있거나, 전용 서버(Dedicated Server)와 공유 서버(Shared Server) 간 혼용 설정이 잘못된 경우에도 리스너가 적합한 핸들러를 찾지 못합니다. 특히 RAC(Real Application Clusters) 환경에서는 서비스 등록(Service Registration) 문제와 맞물려 더욱 복잡한 양상을 띠기도 합니다.


해결 방법

원인 1 해결: PROCESSES / SESSIONS 파라미터 상향 조정

먼저 현재 상태를 진단합니다.

-- 현재 파라미터 값 확인
SELECT name, value
FROM v$parameter
WHERE name IN ('processes', 'sessions', 'transactions');

-- 현재 실제 접속 세션 수 확인
SELECT status, count(*) AS cnt
FROM v$session
GROUP BY status
ORDER BY cnt DESC;

-- 최대 사용 프로세스 수 확인 (PROCESSES 한계 대비)
SELECT resource_name, current_utilization, max_utilization, limit_value
FROM v$resource_limit
WHERE resource_name IN ('processes', 'sessions');

진단 후 max_utilizationlimit_value에 근접하거나 초과하면 즉시 파라미터를 조정해야 합니다.

-- SPFILE을 사용하는 경우 (권장 방식, 재기동 필요)
ALTER SYSTEM SET PROCESSES = 500 SCOPE = SPFILE;
ALTER SYSTEM SET SESSIONS = 555 SCOPE = SPFILE;

-- 변경 후 데이터베이스 재기동
-- SHUTDOWN IMMEDIATE;
-- STARTUP;

-- 재기동 후 반드시 재확인
SELECT name, value
FROM v$parameter
WHERE name IN ('processes', 'sessions');

> ⚠️ PROCESSES 파라미터는 Static 파라미터이므로 반드시 데이터베이스 재기동이 필요합니다.


원인 2 해결: 유휴 세션 정리 및 커넥션 누수 탐지

-- 장시간 INACTIVE 상태인 세션 식별
SELECT sid, serial#, username, status, machine, program,
       last_call_et AS idle_seconds,
       to_char(logon_time, 'YYYY-MM-DD HH24:MI:SS') AS logon_time
FROM v$session
WHERE status = 'INACTIVE'
  AND last_call_et > 3600  -- 1시간 이상 유휴 세션
  AND username IS NOT NULL
ORDER BY last_call_et DESC;

-- 특정 유휴 세션 강제 종료 (SID, SERIAL# 확인 후 적용)
ALTER SYSTEM KILL SESSION '123,456' IMMEDIATE;

-- 커넥션 누수 의심 프로그램별 세션 수 집계
SELECT program, machine, status, count(*) AS session_count
FROM v$session
WHERE username IS NOT NULL
GROUP BY program, machine, status
ORDER BY session_count DESC;

프로파일을 통해 유휴 시간 제한을 설정하면 근본적인 예방이 가능합니다.

-- 유휴 세션 자동 종료 프로파일 생성
CREATE PROFILE app_user_profile LIMIT
  IDLE_TIME          30    -- 30분 유휴 시 자동 종료
  CONNECT_TIME       480   -- 최대 접속 유지 시간 8시간
  SESSIONS_PER_USER  10;   -- 사용자당 최대 세션 수

-- 프로파일 적용
ALTER USER app_user PROFILE app_user_profile;

원인 3 해결: 리스너 및 Shared Server 설정 점검

-- Dispatcher 현황 확인 (Shared Server 환경)
SELECT name, status, dispatchers, sessions
FROM v$dispatcher_config;

SELECT network, status, owned, messages
FROM v$dispatcher;

-- Shared Server 현황 확인
SELECT name, status, requests
FROM v$shared_server;

-- Dispatcher 수 동적 조정 (재기동 불필요)
ALTER SYSTEM SET DISPATCHERS = '(PROTOCOL=TCP)(DISPATCHERS=5)' SCOPE = BOTH;

-- 리스너 상태 확인 (OS 레벨, SQL*Plus 외부에서 실행)
-- lsnrctl status
-- lsnrctl reload

예방 방법

1. 모니터링 자동화 및 임계치 알림 설정

v$resource_limit 뷰를 주기적으로 폴링하는 모니터링 스크립트를 구축하여, PROCESSESSESSIONS의 사용률이 80%를 초과하면 즉시 DBA에게 알림이 가도록 설정해야 합니다. Oracle Enterprise Manager(OEM) 또는 Prometheus + Grafana 등 외부 모니터링 도구와 연동하면 더욱 효과적이며, 임계치 초과 전에 선제적으로 파라미터를 조정하거나 불필요한 세션을 정리할 수 있습니다.

-- 모니터링 쿼리 예시 (스케줄러 잡으로 등록 권장)
SELECT resource_name,
       current_utilization,
       max_utilization,
       limit_value,
       ROUND(current_utilization / NULLIF(limit_value, 0) * 100, 2) AS usage_pct
FROM v$resource_limit
WHERE resource_name IN ('processes', 'sessions')
  AND limit_value != 'UNLIMITED';

2. 애플리케이션 레이어 커넥션 풀 표준화

모든 애플리케이션 팀이 Oracle UCP(Universal Connection Pool), HikariCP, DBCP2 등 검증된 커넥션 풀 라이브러리를 사용하고, maxPoolSize, connectionTimeout, idleTimeout, maxLifetime 등의 파라미터를 DBA와 협의하여 표준값을 정의하도록 거버넌스를 수립해야 합니다. 또한 배포 파이프라인에 커넥션 누수 탐지 도구(예: LeakDetectionThreshold in HikariCP)를 통합하여 운영 환경 투입 전에 문제를 사전 차단해야 합니다.


관련 에러

| 에러 코드 | 설명 |

|———–|——|

| ORA-12520 | TNS: listener could not find available handler for requested type of server — Shared Server 핸들러 부족 시 발생 |

| ORA-00018 | maximum number of sessions exceeded — SESSIONS 파라미터 한계 초과 |

| ORA-00020 | maximum number of processes exceeded — PROCESSES 파라미터 한계 초과 |

| ORA-12519 | TNS: no appropriate service handler found — 서비스 핸들러를 찾지 못할 때 발생하며 ORA-12516과 유사한 상황에서 발생 |

| ORA-01034 | ORACLE not available — 인스턴스 자체가 응답하지 않는 경우 |

ORA-12516은 단독으로 발생하기보다는 ORA-00020, ORA-00018과 연달아 발생하는 경우가 많으므로, Alert Log와 함께 v$resource_limit 를 동시에 확인하는 습관을 들이시기 바랍니다.


DBMS 에러 코드 시리즈

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

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

댓글 남기기