How to fix 01006: privilege_not_revoked in PostgreSQL
SQLSTATE 01006 is a warning that PostgreSQL raises when a REVOKE statement attempts to remove privileges that were never granted. The operation completes successfully but serves as a notice that no actual privilege changes occurred, helping you audit your permission management scripts.
Quick fix
Fixes 01006: privilege_not_revoked
-- For table privileges
SELECT grantee, privilege_type, is_grantable
FROM information_schema.table_privileges
WHERE table_schema = 'public'
AND table_name = 'your_table'
AND grantee = 'target_user';
-- For schema privileges
SELECT grantee, privilege_type, is_grantable
FROM information_schema.schema_privileges
WHERE schema_name = 'public'
AND grantee = 'target_user';
-- For database privileges
SELECT datname, usename, usecreatedb, usesuper
FROM pg_database d, pg_user u
WHERE d.datname = current_database()
AND usename = 'target_user';- Verify the current privilege state before revoking
- Review REVOKE statement syntax and scope
- Check role inheritance and membership chains
- Implement conditional privilege management
-- For table privilegesSELECT grantee, privilege_type, is_grantableFROM information_schema.table_privilegesWHERE table_schema = 'public'AND table_name = 'your_table'AND grantee = 'target_user';-- For schema privilegesSELECT grantee, privilege_type, is_grantableFROM information_schema.schema_privilegesWHERE schema_name = 'public'AND grantee = 'target_user';-- For database privilegesSELECT datname, usename, usecreatedb, usesuperFROM pg_database d, pg_user uWHERE d.datname = current_database()AND usename = 'target_user';01006: privilege_not_revoked
What this error means
SQLSTATE 01006 belongs to SQL standard class 01 (warning) and corresponds to the completion condition "warning - privilege not revoked". This warning occurs when you execute a REVOKE statement targeting specific privileges on database objects, but the specified user or role doesn't actually possess those privileges. PostgreSQL processes the REVOKE command normally but raises this warning to inform you that no privileges were actually removed. This is particularly useful in automation scripts and database migration pipelines where you want to ensure privilege management operations have their intended effect.
Typical symptoms
- REVOKE statements complete without error but the client logs/tells you "01006: privilege_not_revoked"
- psql, ORM, or driver output mentions a warning or notice level record with SQLSTATE 01006
- Permission audit scripts show no change in user/role privileges after running REVOKE commands
- Database migration logs contain warnings about privilege operations having no effect
- Automated security compliance checks flag REVOKE statements that didn't modify actual permissions
Common causes
- Attempting to revoke privileges that were never granted to the specified user or role
- REVOKE statements with overly broad or incorrect privilege specifications
- Privileges were previously revoked by another process or administrator
- Role inheritance chains where privileges are granted indirectly through parent roles
- Database object permissions that differ from expected state due to manual interventions or drift
How to fix "01006: privilege_not_revoked"
Check what privileges the target user/role actually has on the database object:
-- For table privileges
SELECT grantee, privilege_type, is_grantable
FROM information_schema.table_privileges
WHERE table_schema = 'public'
AND table_name = 'your_table'
AND grantee = 'target_user';
-- For schema privileges
SELECT grantee, privilege_type, is_grantable
FROM information_schema.schema_privileges
WHERE schema_name = 'public'
AND grantee = 'target_user';
-- For database privileges
SELECT datname, usename, usecreatedb, usesuper
FROM pg_database d, pg_user u
WHERE d.datname = current_database()
AND usename = 'target_user';This confirms whether the privileges you're trying to revoke actually exist.
Ensure your REVOKE command targets the correct privileges, objects, and roles:
-- Common patterns that might cause 01006:
REVOKE INSERT, UPDATE ON TABLE employees FROM analyst_role;
-- If analyst_role only has SELECT, you'll get 01006 for INSERT and UPDATE
REVOKE ALL ON SCHEMA public FROM app_user;
-- If app_user has no privileges on public schema, you'll get 01006
REVOKE EXECUTE ON FUNCTION calculate_bonus() FROM hr_user;
-- If hr_user was never granted EXECUTE, you'll get 01006Consider using IF EXISTS patterns or checking privilege state before issuing REVOKE commands in automation.
Privileges can be granted indirectly through role membership:
-- See what roles the target user belongs to
SELECT rolname FROM pg_roles
WHERE pg_has_role('target_user', oid, 'member');
-- Check privileges granted to parent roles
SELECT r.rolname, t.privilege_type
FROM pg_roles r
CROSS JOIN unnest(ARRAY['SELECT', 'INSERT', 'UPDATE', 'DELETE', 'TRUNCATE', 'REFERENCES', 'TRIGGER']) t(privilege_type)
WHERE has_table_privilege(r.rolname, 'your_table', t.privilege_type)
AND r.rolname IN (SELECT rolname FROM pg_roles WHERE pg_has_role('target_user', oid, 'member'));A user might have privileges through role membership rather than direct grants.
For automation scripts, consider checking privilege existence before revoking:
-- Example: Only revoke if privilege exists
DO $$
BEGIN
IF EXISTS (
SELECT 1 FROM information_schema.table_privileges
WHERE grantee = 'target_user'
AND table_schema = 'public'
AND table_name = 'employees'
AND privilege_type = 'INSERT'
) THEN
REVOKE INSERT ON TABLE employees FROM target_user;
END IF;
END $$;
-- Or use a function that suppresses the warning
CREATE OR REPLACE FUNCTION safe_revoke_privilege(
p_username text,
p_table_schema text,
p_table_name text,
p_privilege text
) RETURNS void AS $$
BEGIN
EXECUTE format('REVOKE %s ON TABLE %I.%I FROM %I',
p_privilege, p_table_schema, p_table_name, p_username);
EXCEPTION WHEN OTHERS THEN
-- Log but don't fail
RAISE NOTICE 'Could not revoke % on %.% from %: %',
p_privilege, p_table_schema, p_table_name, p_username, SQLERRM;
END;
$$ LANGUAGE plpgsql;This approach makes privilege management scripts idempotent.
Set up auditing to track privilege modifications:
-- Enable logging of privilege commands
ALTER DATABASE yourdb SET log_statement = 'ddl';
-- Or use event triggers for more detailed auditing
CREATE OR REPLACE FUNCTION audit_privilege_changes()
RETURNS event_trigger AS $$
DECLARE
r record;
BEGIN
FOR r IN SELECT * FROM pg_event_trigger_ddl_commands()
LOOP
IF r.command_tag IN ('GRANT', 'REVOKE') THEN
INSERT INTO privilege_audit_log
(event_time, username, command_tag, object_type, object_identity)
VALUES (now(), current_user, r.command_tag, r.object_type, r.object_identity);
END IF;
END LOOP;
END;
$$ LANGUAGE plpgsql;
CREATE EVENT TRIGGER audit_privileges ON ddl_command_end
WHEN TAG IN ('GRANT', 'REVOKE')
EXECUTE FUNCTION audit_privilege_changes();Regular audits help identify when REVOKE warnings indicate configuration drift or unexpected privilege states.
Advanced notes
SQLSTATE 01006 is a standard SQL warning, not PostgreSQL-specific. It helps maintain idempotency in privilege management scripts—attempting to revoke non-existent privileges doesn't fail but warns you. In production automation, you might want to suppress this warning using client_min_messages or handle it in your application logic. The warning is particularly valuable in Infrastructure-as-Code scenarios where you want to know if your declared privilege state differs from actual state.
Frequently asked questions
- What does "01006: privilege_not_revoked" mean?
- SQLSTATE 01006 belongs to SQL standard class 01 (warning) and corresponds to the completion condition "warning - privilege not revoked". This warning occurs when you execute a REVOKE statement targeting specific privileges on database objects, but the specified user or role doesn't actually possess those privileges. PostgreSQL processes the REVOKE command normally but raises this warning to inform you that no privileges were actually removed.
- How do I fix "01006: privilege_not_revoked"?
- SQLSTATE 01006 is a warning that PostgreSQL raises when a REVOKE statement attempts to remove privileges that were never granted. The operation completes successfully but serves as a notice that no actual privilege changes occurred, helping you audit your permission management scripts.
- What causes "01006: privilege_not_revoked"?
- Attempting to revoke privileges that were never granted to the specified user or role REVOKE statements with overly broad or incorrect privilege specifications Privileges were previously revoked by another process or administrator
- Is the "01006: privilege_not_revoked" error serious?
- It is a low-severity error — more of a blocker than a risk. The steps above resolve it.
Official resources & further reading
- 📚PostgreSQL Official Documentation
- 📖postgresql.org - errcodes appendix(Official Docs)
- 📖postgresql.org - sql revoke(Official Docs)
- 📖postgresql.org - ddl priv(Official Docs)
- 💬stackoverflow.com - postgresql+privileges(Stack Overflow)
- 🐙github.com - privilegecmds.c(GitHub)