2026년 09월 26일 | DBMS Error 가이드
이 글에서 다루는 내용
ORA-16003 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
ORA-16003 standby database is restricted to read-only access 는?
ORA-16003 에러는 Oracle Data Guard 환경에서 Standby 데이터베이스에 쓰기(DML/DDL) 작업을 시도할 때 발생하는 에러입니다. Standby 데이터베이스는 기본적으로 읽기 전용(Read-Only) 또는 Managed Recovery 모드로 운영되기 때문에, Primary 데이터베이스에서만 허용되는 변경 작업을 Standby에서 실행하려 할 경우 이 에러가 발생합니다. Active Data Guard(ADG) 라이선스가 적용된 환경이라도 Standby 노드에서 직접 데이터를 변경하는 것은 Data Guard 아키텍처의 근본 원칙에 위배되므로, 해당 에러를 통해 시스템이 이를 차단합니다.
주요 발생 원인
- Standby 데이터베이스에서 직접 DML/DDL 수행 시도
가장 흔한 원인으로, 개발자 또는 운영자가 Standby 데이터베이스에 접속하여 INSERT, UPDATE, DELETE, CREATE 등의 쓰기 작업을 실행하려 할 때 발생합니다. Standby 데이터베이스는 Primary로부터 Redo 로그를 받아 적용하는 역할만 수행하며, 독립적인 데이터 변경은 Data Guard 동기화를 깨뜨릴 수 있어 Oracle이 이를 원천 차단합니다.
- 애플리케이션이 Primary/Standby 연결을 구분하지 못하는 경우
애플리케이션의 Connection Pool 설정이나 Load Balancer 구성에서 Primary와 Standby의 역할을 구분하지 않고 동일한 서비스로 묶어 두었을 경우, 쓰기 요청이 Standby로 라우팅되어 ORA-16003이 발생합니다. 특히 Oracle RAC와 Data Guard를 함께 사용하는 환경이나, JDBC URL에 다중 호스트를 나열한 경우 이런 문제가 발생할 가능성이 높습니다.
- Failover/Switchover 이후 잘못된 연결 설정 유지
Switchover 또는 Failover가 발생한 이후, 기존 Primary 역할을 하던 DB가 Standby로 전환되었음에도 불구하고 애플리케이션이나 배치 작업이 여전히 이전 접속 정보를 사용하여 해당 노드에 쓰기 요청을 보낼 경우 이 에러가 발생합니다. 역할 전환 후 TNS 설정, Connection String, DB 링크 등을 전면 재검토하지 않으면 반복적으로 이 에러가 발생하게 됩니다.
해결 방법
1. 현재 데이터베이스 역할 확인
우선 접속한 데이터베이스가 Primary인지 Standby인지 반드시 확인합니다.
-- 현재 DB 역할 및 오픈 모드 확인
SELECT NAME, DB_UNIQUE_NAME, DATABASE_ROLE, OPEN_MODE, PROTECTION_MODE
FROM V$DATABASE;
-- 출력 예시
-- NAME DB_UNIQUE_NAME DATABASE_ROLE OPEN_MODE PROTECTION_MODE
-- ORCL ORCL_STB PHYSICAL STANDBY READ ONLY WITH APPLY MAXIMUM PERFORMANCE
위 쿼리에서 DATABASE_ROLE이 PHYSICAL STANDBY 또는 LOGICAL STANDBY로 표시된다면, 해당 DB는 Standby이므로 쓰기 작업을 수행할 수 없습니다. 반드시 Primary 데이터베이스로 접속을 전환해야 합니다.
2. Primary 데이터베이스 확인 및 연결 전환
-- Data Guard 구성 전체 상태 확인 (Primary에서 실행)
SELECT INST_ID, NAME, DB_UNIQUE_NAME, DATABASE_ROLE, OPEN_MODE
FROM GV$DATABASE;
-- Data Guard Broker를 사용하는 경우 Primary 확인
-- DGMGRL 명령어 (OS 레벨에서 실행)
-- dgmgrl sys/password@primary_tns
-- DGMGRL> show configuration;
-- DGMGRL> show database verbose 'DB_UNIQUE_NAME';
-- TNS 설정에서 Primary 서비스로 연결하는 예시 (sqlplus)
-- sqlplus scott/tiger@PRIMARY_SERVICE
-- Primary 서비스 확인
SELECT NAME, NETWORK_NAME, ROLE, FAILOVER_TYPE
FROM DBA_SERVICES
WHERE ROLE = 'PRIMARY';
3. Active Data Guard 환경에서 Read-Only 세션 확인
Active Data Guard를 사용하는 경우 Standby에서 SELECT는 허용되지만 DML은 허용되지 않습니다. 아래 쿼리로 현재 세션의 작업을 확인하세요.
-- 현재 Standby에 접속 중인 세션 확인
SELECT SID, SERIAL#, USERNAME, STATUS, PROGRAM, SQL_ID
FROM V$SESSION
WHERE USERNAME IS NOT NULL
AND STATUS = 'ACTIVE';
-- 특정 SQL이 DML인지 확인
SELECT SQL_ID, SQL_TEXT, COMMAND_TYPE
FROM V$SQL
WHERE SQL_ID = '&sql_id';
-- COMMAND_TYPE: 2=INSERT, 6=UPDATE, 7=DELETE, 26=LOCK TABLE 등
4. Switchover 후 역할 전환 및 쓰기 허용 (운영 판단 필요)
만약 Standby를 Primary로 전환해야 하는 경우, 다음 절차로 Switchover를 수행합니다.
-- [기존 Primary에서 실행] Switchover 준비 상태 확인
SELECT SWITCHOVER_STATUS FROM V$DATABASE;
-- 'TO STANDBY' 또는 'SESSIONS ACTIVE' 가 나와야 Switchover 가능
-- [기존 Primary에서 실행] Switchover 수행
ALTER DATABASE COMMIT TO SWITCHOVER TO PHYSICAL STANDBY WITH SESSION SHUTDOWN;
-- [기존 Standby에서 실행] Primary로 전환
ALTER DATABASE COMMIT TO SWITCHOVER TO PRIMARY WITH SESSION SHUTDOWN;
-- [새로운 Primary에서 실행] DB 오픈
ALTER DATABASE OPEN;
5. 애플리케이션 서비스 분리 설정 (권장)
-- Primary 전용 서비스 생성 (Primary DB에서 실행)
BEGIN
DBMS_SERVICE.CREATE_SERVICE(
service_name => 'WRITE_SERVICE',
network_name => 'WRITE_SERVICE',
goal => DBMS_SERVICE.GOAL_NONE,
dtp => FALSE
);
END;
/
-- 서비스 시작
EXEC DBMS_SERVICE.START_SERVICE('WRITE_SERVICE');
-- Standby 전용 읽기 서비스 확인
SELECT NAME, ROLE FROM DBA_SERVICES WHERE ROLE IN ('PRIMARY', 'PHYSICAL_STANDBY');
예방 방법
- DB Role 기반의 서비스 분리 및 Connection 관리 자동화
Oracle Data Guard Broker와 함께 역할 기반 서비스(Role-Based Services)를 구성하면, Switchover/Failover 발생 시 자동으로 서비스가 올바른 노드에서 기동됩니다. 애플리케이션의 Connection Pool에는 반드시 PRIMARY 역할 서비스만 쓰기 작업에 사용하도록 설정하고, 읽기 전용 쿼리는 PHYSICAL_STANDBY 역할 서비스로 분리하는 것이 Best Practice입니다. 주기적으로 V$DATABASE의 DATABASE_ROLE을 모니터링하는 스크립트를 운영 체계에 포함시키면 역할 혼선을 사전에 예방할 수 있습니다.
- Switchover/Failover 이후 체크리스트 수행 의무화
역할 전환이 발생한 직후에는 반드시 표준화된 Post-Switchover 체크리스트를 수행해야 합니다. 여기에는 TNS 별칭 업데이트, 애플리케이션 Connection String 재설정, DB 링크 재생성, 배치 JOB의 대상 DB 검증 등이 포함되어야 합니다. 이를 자동화하기 위해 Data Guard Broker의 FastStart Failover(FSFO)와 Oracle Notification Service(ONS)를 활용하면 대부분의 애플리케이션 재연결을 자동으로 처리할 수 있습니다.
관련 에러
- ORA-16000: 데이터베이스가 읽기 전용 모드로 오픈되어 있을 때 발생하며, ORA-16003과 함께 나타나는 경우가 많습니다.
- ORA-01109: 데이터베이스가 오픈되지 않은 상태에서 접근 시 발생하며, Standby가 Mount 상태일 때 주로 나타납니다.
- ORA-16401: Data Guard Broker 환경에서 Standby 데이터베이스로의 DML 차단 시 나타나는 관련 에러입니다.
- ORA-16826: Fast Start Failover 관련 설정 불일치 시 발생하며, ORA-16003과 함께 Failover 시나리오에서 자주 동반됩니다.
- ORA-01552: Standby 환경에서 임시 Undo 관련 작업 시 발생할 수 있는 연관 에러입니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.