How to fix 01006: privilege_not_revoked in PostgreSQL

PostgreSQLINTERMEDIATELOWUpdated Dec 22, 2025· 151 views

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';
  1. Verify the current privilege state before revoking
  2. Review REVOKE statement syntax and scope
  3. Check role inheritance and membership chains
  4. Implement conditional privilege management
postgresql — error
-- 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';
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

  1. Attempting to revoke privileges that were never granted to the specified user or role
  2. REVOKE statements with overly broad or incorrect privilege specifications
  3. Privileges were previously revoked by another process or administrator
  4. Role inheritance chains where privileges are granted indirectly through parent roles
  5. Database object permissions that differ from expected state due to manual interventions or drift

How to fix "01006: privilege_not_revoked"

1Verify the current privilege state before revoking

Check what privileges the target user/role actually has on the database object:

sql
-- 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.

2Review REVOKE statement syntax and scope

Ensure your REVOKE command targets the correct privileges, objects, and roles:

sql
-- 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 01006

Consider using IF EXISTS patterns or checking privilege state before issuing REVOKE commands in automation.

3Check role inheritance and membership chains

Privileges can be granted indirectly through role membership:

sql
-- 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.

4Implement conditional privilege management

For automation scripts, consider checking privilege existence before revoking:

sql
-- 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.

5Monitor and log privilege changes systematically

Set up auditing to track privilege modifications:

sql
-- 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