2026년 08월 30일 | DBMS Error 가이드
이 글에서 다루는 내용
2B000 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
2B000 dependent privilege descriptors still exist 는?
PostgreSQL 에러 코드 2B000은 dependent privilege descriptors still exist라는 메시지로 발생하며, 어떤 데이터베이스 오브젝트를 삭제하거나 변경하려 할 때 해당 오브젝트에 종속된 권한(privilege) 정보가 아직 남아 있을 경우 발생합니다. 쉽게 말해, 특정 역할(Role)이나 사용자(User)가 보유한 권한이 삭제 대상 오브젝트와 연결되어 있어 PostgreSQL이 안전하게 작업을 진행할 수 없다고 판단한 것입니다. 주로 DROP ROLE, DROP USER, REVOKE 등의 명령어를 실행할 때 나타나며, 권한 구조가 복잡한 대규모 운영 환경에서 자주 마주치게 되는 에러입니다.
주요 발생 원인
1. 역할(Role) 삭제 시 해당 역할에 부여된 권한이 남아 있는 경우
가장 흔한 원인으로, DROP ROLE 또는 DROP USER 명령을 실행할 때 해당 역할이 다른 오브젝트(테이블, 시퀀스, 함수 등)에 대한 권한을 아직 보유하고 있거나, 다른 역할에게 권한을 부여한 이력이 있는 경우 발생합니다. PostgreSQL은 권한의 참조 무결성을 보호하기 위해, 종속된 권한 디스크립터가 존재하는 한 역할 삭제를 허용하지 않습니다. 즉, 역할을 삭제하기 전에 반드시 해당 역할이 보유한 모든 권한을 먼저 회수(REVOKE)하거나 오브젝트 소유권을 이전해야 합니다.
2. 역할 간 권한 부여(GRANT … TO) 관계가 남아 있는 경우
한 역할이 다른 역할에게 권한을 부여(GRANT)한 상태에서 부여자(grantor) 역할을 삭제하려 할 때 이 에러가 발생합니다. PostgreSQL의 권한 체계는 “누가 누구에게 권한을 주었는가”를 추적하는데, 부여자 정보가 시스템 카탈로그에 남아 있으면 해당 역할을 안전하게 제거할 수 없습니다. 이 경우 REVOKE를 통해 권한 부여 관계를 먼저 정리한 뒤 역할을 삭제해야 합니다.
3. 오브젝트 소유자(Owner) 변경 없이 소유자 역할을 삭제하려는 경우
특정 역할이 테이블, 뷰, 함수, 스키마 등 다양한 오브젝트의 소유자(owner)로 등록되어 있을 때, 해당 역할을 삭제하면 오브젝트들이 고아 상태가 되므로 PostgreSQL이 삭제를 거부합니다. 이 상황은 단순히 권한 회수만으로 해결되지 않으며, REASSIGN OWNED BY 명령으로 소유권을 다른 역할로 이전하고 DROP OWNED BY 명령으로 잔여 권한을 모두 정리해야 합니다.
해결 방법
원인 1 해결: 역할이 보유한 권한 전체 회수
먼저 어떤 권한이 남아 있는지 확인합니다.
-- 특정 역할이 보유한 테이블 권한 확인
SELECT grantee, table_schema, table_name, privilege_type
FROM information_schema.role_table_grants
WHERE grantee = 'target_role';
-- 특정 역할이 보유한 스키마 권한 확인
SELECT nspname, nspacl
FROM pg_namespace
WHERE nspacl::text LIKE '%target_role%';
확인 후 아래와 같이 권한을 회수합니다.
-- 특정 테이블에 대한 권한 회수
REVOKE ALL PRIVILEGES ON TABLE public.my_table FROM target_role;
-- 스키마 내 모든 테이블에 대한 권한 일괄 회수
REVOKE ALL PRIVILEGES ON ALL TABLES IN SCHEMA public FROM target_role;
-- 시퀀스 권한 회수
REVOKE ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public FROM target_role;
-- 함수 권한 회수
REVOKE ALL PRIVILEGES ON ALL FUNCTIONS IN SCHEMA public FROM target_role;
-- 스키마 자체 권한 회수
REVOKE ALL PRIVILEGES ON SCHEMA public FROM target_role;
-- 데이터베이스 권한 회수
REVOKE ALL PRIVILEGES ON DATABASE mydb FROM target_role;
원인 2 해결: 역할 간 권한 부여 관계 정리
-- 역할 간 권한 부여 관계 확인 (pg_auth_members)
SELECT
r.rolname AS role_name,
m.rolname AS member_name,
g.rolname AS granted_by
FROM pg_auth_members am
JOIN pg_roles r ON r.oid = am.roleid
JOIN pg_roles m ON m.oid = am.member
JOIN pg_roles g ON g.oid = am.grantor
WHERE r.rolname = 'target_role' OR m.rolname = 'target_role';
-- 역할 멤버십 해제
REVOKE target_role FROM other_role;
-- 부여자가 target_role인 경우 권한 연쇄 회수
REVOKE GRANT OPTION FOR SELECT ON TABLE public.my_table FROM target_role CASCADE;
원인 3 해결: 소유권 이전 후 역할 삭제
-- 1단계: 해당 역할이 소유한 모든 오브젝트를 다른 역할로 이전
REASSIGN OWNED BY target_role TO postgres;
-- 2단계: 해당 역할에 남아 있는 모든 권한 제거
DROP OWNED BY target_role;
-- 3단계: 역할 삭제
DROP ROLE target_role;
종합 정리 스크립트 (실무 권장)
운영 환경에서는 아래 순서로 진행하면 대부분의 케이스를 커버할 수 있습니다.
-- 트랜잭션으로 묶어 안전하게 처리
BEGIN;
-- 소유 오브젝트 이전
REASSIGN OWNED BY target_role TO postgres;
-- 모든 권한 및 기본 권한(default privileges) 제거
DROP OWNED BY target_role;
-- 역할 삭제
DROP ROLE IF EXISTS target_role;
COMMIT;
예방 방법
1. 역할 삭제 전 체크리스트 자동화
역할을 삭제하기 전에 아래 쿼리를 통해 사전 점검하는 습관을 들이거나, CI/CD 파이프라인 또는 DBA 표준 운영 절차(SOP)에 포함시켜 자동화하세요. 이를 통해 운영 중 실수로 발생하는 에러를 사전에 차단할 수 있습니다.
-- 역할 삭제 전 사전 점검 쿼리
SELECT
'TABLE' AS object_type,
table_schema || '.' || table_name AS object_name,
privilege_type
FROM information_schema.role_table_grants
WHERE grantee = 'target_role'
UNION ALL
SELECT
'MEMBERSHIP',
r.rolname,
'MEMBER'
FROM pg_auth_members am
JOIN pg_roles r ON r.oid = am.roleid
WHERE am.member = (SELECT oid FROM pg_roles WHERE rolname = 'target_role');
2. 권한 관리 체계를 역할 그룹 기반으로 단순화
개별 사용자에게 직접 권한을 부여하는 방식 대신, 기능별 역할 그룹(예: role_readonly, role_readwrite, role_admin)을 생성하고 사용자 역할에 그룹 역할을 부여하는 계층적 권한 관리 체계를 도입하세요. 이렇게 하면 특정 사용자를 삭제할 때 개별 권한 회수 없이 그룹 멤버십만 해제하면 되므로, 2B000 에러 발생 가능성을 크게 줄일 수 있습니다.
-- 그룹 역할 생성
CREATE ROLE role_readonly NOLOGIN;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO role_readonly;
-- 사용자에게 그룹 역할 부여 (직접 권한 부여 지양)
CREATE ROLE app_user LOGIN PASSWORD 'secret';
GRANT role_readonly TO app_user;
-- 사용자 삭제 시: 멤버십만 해제하면 됨
REVOKE role_readonly FROM app_user;
DROP ROLE app_user;
관련 에러
42501(insufficient_privilege): 권한이 없는 오브젝트에 접근하려 할 때 발생하는 에러로, 권한 관리 체계가 잘못 설계되었을 때2B000과 함께 자주 마주치게 됩니다.2BP01(dependent_objects_still_exist): 역할 삭제 시 해당 역할이 소유한 오브젝트가 존재할 때 발생하며,2B000과 유사한 맥락에서 발생합니다.REASSIGN OWNED BY로 해결 가능합니다.0LP01(invalid_grant_operation): 잘못된 GRANT 명령 실행 시 발생하며, 권한 부여/회수 과정에서2B000과 연쇄적으로 나타날 수 있습니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.