2026년 08월 01일 | DBMS Error 가이드
이 글에서 다루는 내용
01006 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
01006 privilege not revoked 는?
PostgreSQL 에러 코드 01006은 SQLSTATE 01006으로 분류되며, REVOKE 명령 실행 시 해당 권한이 실제로 취소되지 않았을 때 발생하는 경고(Warning) 성격의 에러입니다. 이 에러는 치명적인 오류가 아닌 경고(Warning) 레벨로, 트랜잭션을 중단시키지는 않지만 권한 관리 측면에서 반드시 인지하고 처리해야 하는 중요한 신호입니다. 주로 존재하지 않는 권한을 회수하려 할 때, 또는 권한을 부여한 사용자와 회수를 시도하는 사용자가 다를 때 발생합니다.
주요 발생 원인
- 대상 사용자가 해당 권한을 애초에 보유하지 않은 경우
가장 흔한 원인으로, 특정 사용자에게 부여된 적 없는 권한을 REVOKE하려 할 때 발생합니다. 예를 들어 user_a에게 orders 테이블에 대한 INSERT 권한을 부여한 적이 없는데 이를 회수하려 하면 01006 경고가 발생합니다. 운영 환경에서 권한 관리 스크립트를 일괄 실행할 때 이 상황이 자주 발생하며, 스크립트 실행 전 현재 권한 상태를 먼저 확인하는 것이 중요합니다.
- 권한을 부여한 주체(Grantor)와 회수를 시도하는 주체가 다른 경우
PostgreSQL의 권한 모델에서는 권한을 부여한 사람(Grantor)만이 해당 권한을 회수할 수 있는 원칙이 있습니다(슈퍼유저 제외). user_b가 user_c에게 권한을 부여했는데, user_a가 이를 회수하려 하면 01006 경고가 발생할 수 있습니다. 이는 조직 내 DBA가 여러 명이거나, 역할(Role) 체계가 복잡할 때 흔히 나타나는 패턴입니다.
- 롤(Role) 상속 구조로 인해 직접 권한이 아닌 상속된 권한을 회수하려는 경우
PostgreSQL은 역할(Role) 기반의 권한 상속 구조를 지원합니다. 사용자가 특정 롤을 통해 간접적으로 권한을 보유하고 있을 때, 해당 사용자에게 직접 그 권한을 REVOKE하려 하면 실제로 회수가 이루어지지 않고 01006 경고가 발생합니다. 롤 멤버십을 통해 상속받은 권한은 해당 롤에서 권한을 제거하거나, 롤 멤버십 자체를 제거해야 합니다.
해결 방법
원인 1 해결: 권한 보유 여부 사전 확인 후 REVOKE 실행
REVOKE 실행 전 information_schema 또는 pg_catalog를 통해 현재 권한 현황을 먼저 조회합니다.
-- 특정 테이블에 대한 권한 보유 현황 조회
SELECT grantee, table_schema, table_name, privilege_type, is_grantable
FROM information_schema.role_table_grants
WHERE table_name = 'orders'
AND grantee = 'user_a';
-- 권한이 존재하는 경우에만 REVOKE 실행
-- (권한 존재 확인 후)
REVOKE INSERT ON TABLE orders FROM user_a;
-- 스키마 전체 권한 조회
SELECT nspname, proacl
FROM pg_catalog.pg_namespace
WHERE nspname = 'public';
원인 2 해결: 올바른 Grantor로 REVOKE 실행 또는 슈퍼유저 사용
-- 현재 권한의 Grantor 확인
SELECT grantor, grantee, table_name, privilege_type
FROM information_schema.role_table_grants
WHERE table_name = 'orders';
-- 슈퍼유저로 전환하여 권한 회수 (모든 grantor의 권한 회수 가능)
-- psql에서 슈퍼유저로 접속 후:
REVOKE ALL PRIVILEGES ON TABLE orders FROM user_c;
-- 특정 Grantor가 부여한 권한만 회수하려면
-- 해당 Grantor 계정으로 접속 후 REVOKE 실행
SET ROLE user_b;
REVOKE SELECT ON TABLE orders FROM user_c;
RESET ROLE;
원인 3 해결: 롤 상속 구조 파악 후 롤 레벨에서 권한 제거
-- 롤 멤버십 구조 확인
SELECT r.rolname AS role_name,
m.rolname AS member_name
FROM pg_auth_members am
JOIN pg_roles r ON r.oid = am.roleid
JOIN pg_roles m ON m.oid = am.member;
-- 롤에 부여된 권한 확인
SELECT grantee, table_name, privilege_type
FROM information_schema.role_table_grants
WHERE grantee = 'readonly_role';
-- 롤에서 권한 제거 (상속받은 사용자 모두에게 적용됨)
REVOKE SELECT ON TABLE orders FROM readonly_role;
-- 또는 롤 멤버십 자체를 제거
REVOKE readonly_role FROM user_a;
-- 권한 회수 후 결과 검증
SELECT grantee, privilege_type
FROM information_schema.role_table_grants
WHERE table_name = 'orders'
AND grantee IN ('user_a', 'readonly_role');
실무용 안전한 REVOKE 스크립트 예제
-- 권한 존재 여부를 확인하고 조건부로 REVOKE하는 함수
DO $$
DECLARE
v_count INTEGER;
BEGIN
-- INSERT 권한 보유 여부 확인
SELECT COUNT(*)
INTO v_count
FROM information_schema.role_table_grants
WHERE grantee = 'user_a'
AND table_name = 'orders'
AND privilege_type = 'INSERT';
IF v_count > 0 THEN
EXECUTE 'REVOKE INSERT ON TABLE orders FROM user_a';
RAISE NOTICE '권한 회수 완료: user_a의 orders 테이블 INSERT 권한';
ELSE
RAISE NOTICE '권한 없음: user_a는 orders 테이블에 INSERT 권한이 없습니다';
END IF;
END;
$$;
예방 방법
- 권한 관리 대장(Privilege Inventory) 운영 및 주기적 감사
조직 내 모든 데이터베이스 권한을 별도 테이블이나 문서로 관리하고, 정기적으로 실제 DB 권한 상태와 대조하는 감사(Audit) 프로세스를 운영하세요. 아래 쿼리를 주기적으로 실행하여 권한 현황을 스냅샷으로 저장해 두면, 변경 이력 추적과 사전 확인이 모두 가능합니다.
“`sql
— 전체 권한 현황 스냅샷 저장 테이블
CREATE TABLE IF NOT EXISTS privilege_audit_log (
audit_date TIMESTAMP DEFAULT NOW(),
grantee TEXT,
table_schema TEXT,
table_name TEXT,
privilege_type TEXT,
is_grantable TEXT
);
— 주기적 스냅샷 저장 (크론잡 등으로 자동화)
INSERT INTO privilege_audit_log
(grantee, table_schema, table_name, privilege_type, is_grantable)
SELECT grantee, table_schema, table_name, privilege_type, is_grantable
FROM information_schema.role_table_grants
WHERE table_schema NOT IN (‘pg_catalog’, ‘information_schema’);
“`
- 권한 부여/회수는 반드시 롤(Role) 기반으로 중앙화하여 관리
개별 사용자에게 직접 권한을 부여하는 방식보다, 업무 역할별 롤(Role)을 만들고 해당 롤에 권한을 집중시키세요. 사용자는 롤 멤버십으로만 관리하면 01006 에러 발생 가능성이 크게 줄어들고, 권한 체계가 단순명료해집니다.
“`sql
— 롤 기반 권한 관리 패턴
CREATE ROLE app_readonly;
CREATE ROLE app_readwrite;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO app_readonly;
GRANT SELECT, INSERT, UPDATE ON ALL TABLES IN SCHEMA public TO app_readwrite;
— 사용자는 롤 멤버십으로만 관리
GRANT app_readonly TO report_user;
GRANT app_readwrite TO app_user;
— 권한 회수도 롤 레벨에서 일관되게
REVOKE app_readonly FROM report_user;
“`
관련 에러
01000WARNING: PostgreSQL 일반 경고의 상위 카테고리로,01006은 이 카테고리에 속합니다.42501insufficient_privilege: 권한이 없는 상태에서 객체에 접근하려 할 때 발생하는 에러로,01006으로 권한 회수가 제대로 되지 않은 후 다른 사용자가 해당 객체 접근 시 발생할 수 있습니다.42000syntax_error_or_access_rule_violation: 권한 관련 SQL 문법 오류 시 발생하며,GRANT/REVOKE문 작성 오류와 함께 나타날 수 있습니다.28000invalid_authorization_specification: 인증 및 권한 설정 자체가 잘못된 경우 발생하며, 권한 체계 전반을 점검할 때 함께 확인해야 합니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.