PostgreSQL 25006 오류 원인과 해결 방법 완벽 가이드

25006
2026년 06월 24일 | DBMS Error 가이드

이 글에서 다루는 내용

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

25006 read only sql transaction 는?

PostgreSQL 에러 코드 25006 (read_only_sql_transaction) 은 읽기 전용(read-only)으로 설정된 트랜잭션 또는 세션에서 데이터를 변경하려는 시도가 발생했을 때 나타나는 에러입니다. 즉, INSERT, UPDATE, DELETE, CREATE, DROP 등의 DML/DDL 문장을 실행하려 했으나 현재 트랜잭션 또는 연결이 쓰기를 허용하지 않는 상태일 때 발생합니다. 이 에러는 주로 Hot Standby(읽기 전용 복제본) 서버에 접속하거나, 트랜잭션을 명시적으로 READ ONLY로 시작했거나, default_transaction_read_only 파라미터가 활성화된 환경에서 자주 마주치게 됩니다.


주요 발생 원인

1. Hot Standby(스탠바이 복제본) 서버에 쓰기 시도

PostgreSQL의 스트리밍 복제(Streaming Replication) 구성에서 스탠바이 서버는 기본적으로 읽기 전용 모드로 동작합니다. 애플리케이션이 연결 문자열이나 로드 밸런서 설정 오류로 인해 스탠바이 서버에 쓰기 쿼리를 보내면 이 에러가 발생합니다. 특히 PgBouncer, HAProxy, AWS RDS Proxy 등의 미들웨어를 사용하는 환경에서 읽기/쓰기 분리(Read/Write Split) 설정이 잘못되었을 때 빈번하게 발생합니다.

2. 트랜잭션이 명시적으로 READ ONLY로 선언된 경우

BEGIN READ ONLY 또는 START TRANSACTION READ ONLY 구문으로 트랜잭션을 시작하면 해당 트랜잭션 내에서는 어떠한 데이터 변경도 허용되지 않습니다. 일부 ORM 프레임워크나 쿼리 빌더 라이브러리가 내부적으로 읽기 쿼리에 대해 자동으로 READ ONLY 트랜잭션을 설정하는 경우가 있으며, 그 블록 안에서 실수로 쓰기 작업이 섞이면 에러가 발생합니다.

3. default_transaction_read_only 파라미터 설정

PostgreSQL의 서버 파라미터 또는 사용자/데이터베이스 수준의 파라미터로 default_transaction_read_only = on이 설정된 경우, 해당 세션에서 시작되는 모든 트랜잭션은 기본적으로 읽기 전용이 됩니다. DBA가 보고용 데이터베이스나 분석용 역할(role)에 이 설정을 적용해 놓은 경우, 해당 계정으로 접속한 애플리케이션이 쓰기를 시도하면 이 에러가 발생합니다. 운영 환경에서 ALTER ROLE 또는 ALTER DATABASE 명령으로 설정된 경우 원인 파악이 어려울 수 있으므로 주의가 필요합니다.


해결 방법

원인 1: 현재 서버가 스탠바이인지 확인 및 마스터 서버로 재연결

우선 현재 접속된 서버가 Primary인지 Standby인지 확인합니다.

-- 현재 서버 역할 확인 (true이면 스탠바이 서버)
SELECT pg_is_in_recovery();

-- 복제 상태 상세 확인
SELECT * FROM pg_stat_replication;

pg_is_in_recovery()true를 반환한다면 해당 서버는 읽기 전용 스탠바이입니다. 쓰기 작업은 반드시 Primary 서버로 연결을 변경해야 합니다. 애플리케이션의 DB 연결 설정(DSN, 환경 변수 등)에서 Primary 호스트로 향하는지 반드시 검토하십시오.

원인 2: READ ONLY 트랜잭션을 READ WRITE로 변경

현재 트랜잭션이 읽기 전용인지 확인하고, 필요시 읽기/쓰기 트랜잭션으로 전환합니다.

-- 현재 트랜잭션의 읽기/쓰기 상태 확인
SHOW transaction_read_only;

-- 읽기/쓰기 트랜잭션으로 명시적 시작
BEGIN READ WRITE;
UPDATE orders SET status = 'shipped' WHERE order_id = 1001;
COMMIT;

-- 또는 트랜잭션 내에서 특성 변경 (트랜잭션 시작 직후에만 가능)
BEGIN;
SET TRANSACTION READ WRITE;
INSERT INTO audit_log (event, created_at) VALUES ('login', NOW());
COMMIT;

원인 3: default_transaction_read_only 설정 확인 및 변경

현재 세션 및 서버/역할 수준의 설정을 확인하고 필요에 따라 조정합니다.

-- 현재 세션의 설정 확인
SHOW default_transaction_read_only;

-- 현재 세션에서만 임시로 변경 (재접속 시 초기화됨)
SET default_transaction_read_only = off;

-- 특정 역할(role)에 대한 설정 변경 (DBA 권한 필요)
ALTER ROLE app_user SET default_transaction_read_only = off;

-- 특정 데이터베이스에 대한 설정 변경
ALTER DATABASE mydb SET default_transaction_read_only = off;

-- 현재 어떤 역할/데이터베이스에 설정이 걸려있는지 확인
SELECT rolname, rolconfig
FROM pg_roles
WHERE rolconfig IS NOT NULL;

-- 데이터베이스 수준 설정 확인
SELECT datname, datacl, datconfig
FROM pg_database
WHERE datconfig IS NOT NULL;

예방 방법

1. 애플리케이션 연결 풀 및 라우팅 설정 명확화

읽기/쓰기 분리 아키텍처를 사용하는 환경에서는 반드시 쓰기 전용 연결 풀과 읽기 전용 연결 풀을 명확히 분리하고, 각 풀에 올바른 엔드포인트(Primary vs Replica)가 연결되어 있는지 주기적으로 검증하는 헬스체크 로직을 도입해야 합니다. PgBouncer를 사용하는 경우 server_check_query를 활용하거나, 애플리케이션 시작 시 SELECT pg_is_in_recovery()를 실행하여 Primary 서버 여부를 사전에 확인하는 습관을 들이는 것이 중요합니다.

2. 역할(Role) 및 데이터베이스 설정의 문서화와 정기 감사

운영 환경에서 ALTER ROLE 또는 ALTER DATABASE를 통해 default_transaction_read_only와 같은 파라미터를 변경할 경우 반드시 변경 이력을 문서화하고, 정기적인 DB 설정 감사(Audit)를 수행해야 합니다. 아래 쿼리를 정기 모니터링 스크립트에 포함시켜 예상치 못한 설정 변경을 조기에 감지하는 것을 권장합니다.

-- 정기 감사용 쿼리: read_only 설정이 걸린 역할/DB 목록 추출
SELECT
    'ROLE' AS object_type,
    rolname AS object_name,
    unnest(rolconfig) AS config_entry
FROM pg_roles
WHERE rolconfig::text LIKE '%read_only%'

UNION ALL

SELECT
    'DATABASE' AS object_type,
    datname AS object_name,
    unnest(datconfig) AS config_entry
FROM pg_database
WHERE datconfig::text LIKE '%read_only%';

관련 에러

  • 25001 (active_sql_transaction): 이미 활성화된 트랜잭션 내에서 트랜잭션 특성을 변경하려 할 때 발생합니다.
  • 25P02 (in_failed_sql_transaction): 이전 명령이 실패한 트랜잭션 블록 내에서 추가 명령을 실행하려 할 때 발생합니다. ROLLBACK 후 재시도가 필요합니다.
  • 55P04 (unsafe_new_transaction_on_standby): 스탠바이 서버에서 허용되지 않는 특정 작업을 수행하려 할 때 발생하는 에러로, 25006과 함께 스탠바이 환경에서 자주 등장합니다.
  • 42501 (insufficient_privilege): 읽기 전용 에러와 혼동되는 경우가 있지만, 이는 권한 부족으로 인한 에러로 원인 진단 시 명확히 구분이 필요합니다.

DBMS 에러 코드 시리즈

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

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

댓글 남기기