| Lesson 8 |
Revoking System Privileges |
| Objective |
Revoke privileges and roles from Oracle users safely and correctly. |
Revoking Privileges and Roles in Oracle AI Database 26ai
REVOKE removes a capability you previously granted, and it takes effect immediately, even
against a user who is currently connected. Commands relying on the removed privilege
start failing right away, not at the user's next login. That immediacy is exactly why
revoking safely means understanding what you're about to do before you do it, not
discovering the consequences afterward.
Quick Examples
REVOKE CREATE USER, CREATE SESSION FROM jeff;
REVOKE RESOURCE FROM app_runtime;
REVOKE EXECUTE ANY PROCEDURE FROM reporting_svc;
REVOKE CONNECT FROM PUBLIC;
That last one deserves a pause before you ever run it for real: revoking from PUBLIC
affects every user who relied on that public grant, not just the account you had in mind.
Syntax Reference
Revoking system privileges and roles:
REVOKE { system_privilege | role }
[, { system_privilege | role } ]...
FROM { user | role | PUBLIC }
[, { user | role | PUBLIC } ]...
[ CONTAINER = { CURRENT | ALL } ];
For comparison, the matching GRANT syntax:
GRANT { system_privilege | role }
[, { system_privilege | role } ]...
TO { user | role | PUBLIC }
[, { user | role | PUBLIC } ]...
[ WITH ADMIN OPTION ]
[ CONTAINER = { CURRENT | ALL } ];
Inventory Before You Revoke Anything
Revoking blindly, based on memory of what you think was granted, is how safe cleanups
turn into outages. Before touching a real account, check what is actually there across
every category a privilege or role could belong to:
-- System privileges
SELECT privilege, admin_option, common, inherited
FROM dba_sys_privs
WHERE grantee = 'SCOTT';
-- Schema privileges
SELECT privilege, schema, admin_option, common
FROM dba_schema_privs
WHERE grantee = 'SCOTT';
-- Roles
SELECT granted_role, admin_option, default_role, common
FROM dba_role_privs
WHERE grantee = 'SCOTT';
-- Object privileges
SELECT owner, table_name, privilege, grantable, grantor
FROM dba_tab_privs
WHERE grantee = 'SCOTT';
-- Column privileges
SELECT owner, table_name, column_name, privilege, grantable
FROM dba_col_privs
WHERE grantee = 'SCOTT';
The COMMON and INHERITED columns matter here specifically because every 26ai database is
a multitenant container database: a grant made with CONTAINER=ALL has to be revoked the
same way, and querying these columns first tells you which approach the grant actually
needs before you attempt anything.
Who Can Revoke What
Anyone holding ADMIN OPTION on a specific privilege or role, or holding the broader GRANT
ANY PRIVILEGE or GRANT ANY ROLE, can revoke it, and critically, the revoker does not have
to be the original grantor. One notable exception: a user cannot revoke a role from
themselves.
Schema privileges follow a parallel but distinct authorization path: you can revoke one
if you own the schema, hold that schema privilege with ADMIN OPTION, or hold GRANT ANY
SCHEMA PRIVILEGE.
REVOKE SELECT ANY TABLE ON SCHEMA hr FROM scott;
REVOKE INSERT ANY TABLE ON SCHEMA hr FROM app_role;
Object privileges work differently again. You can revoke an object privilege you
personally granted, or revoke on the owner's behalf if you hold GRANT ANY OBJECT
PRIVILEGE. What you cannot do is revoke a grant someone else made using their own WITH
GRANT OPTION directly from the person they granted it to; instead, you revoke from the
original grantor, and the revoke cascades down from there automatically.
REVOKE SELECT, INSERT ON hr.employees FROM scott;
REVOKE ALL ON hr.employees FROM scott;
REVOKE SELECT ON hr.employees FROM PUBLIC;
What Actually Cascades, and What Doesn't
This is where "safe" genuinely earns its keep. Cascade behavior differs meaningfully by
what you're revoking, and assuming the wrong direction is the single most common way a
revoke produces a surprise:
| What you revoke |
Cascades? |
Effect |
| System privilege |
No |
Objects already created stay in place. The user simply cannot create more. |
| Role |
Not to nested roles |
The user or role immediately loses that role's privileges. Any nested role that had
been granted to the revoked role stays granted to it; the nesting itself is untouched. |
| Object privilege without GRANT OPTION |
No |
The grantee simply loses that privilege. |
| Object privilege with GRANT OPTION |
Yes |
Every downstream grant the grantee made to others is revoked automatically as well. |
| REFERENCES |
Only with CASCADE CONSTRAINTS |
Dependent foreign-key constraints are dropped. Without the clause, the REVOKE fails
outright if such constraints exist. |
| Type EXECUTE with dependents |
Restricted by default |
Fails if tables or other types depend on it, unless the revoke uses FORCE, covered
earlier in this module. |
| Common grant (CONTAINER=ALL) |
Must match scope |
A commonly granted privilege can only be revoked with CONTAINER=ALL; CONTAINER=CURRENT
does not touch it, and vice versa for a locally granted one. |
The REFERENCES case is worth a concrete example, since dropping constraints is exactly
the kind of side effect worth confirming before it happens rather than after:
REVOKE REFERENCES ON hr.employees FROM oe CASCADE CONSTRAINTS;
This drops any foreign-key constraints oe created using that REFERENCES privilege. Check
what those constraints actually are first:
SELECT owner, constraint_name, table_name, r_owner, r_constraint_name
FROM dba_constraints
WHERE constraint_type = 'R'
AND r_owner = 'HR'
AND r_constraint_name IN (
SELECT constraint_name FROM dba_constraints
WHERE owner = 'HR' AND table_name = 'EMPLOYEES'
);
Revoking a Role from a Program Unit
Beyond users and roles, current Oracle releases also support code-based access control:
granting or revoking a role directly on a specific package, procedure, or function,
rather than on the user who owns it. This lets a role apply only while that specific
program unit is executing, distinct from the privileges the owning user holds everywhere
else:
REVOKE clerk_admin FROM PACKAGE psmith.checkstats_pkg;
REVOKE ALL FROM FUNCTION hr.func2;
Invoker's-Rights Privilege Inheritance
A related, more specialized mechanism worth knowing about: INHERIT PRIVILEGES controls
whether an invoker's-rights procedure owned by one user can execute using another user's
privileges when that second user calls it. Revoking this specifically closes that
inheritance path without touching either user's own direct privileges:
REVOKE INHERIT PRIVILEGES ON USER jward FROM ebrown;
REVOKE INHERIT PRIVILEGES ON USER jward FROM PUBLIC;
A Safe Operating Procedure
- Do not revoke from Oracle-maintained accounts such as SYS, SYSTEM,
AUDSYS, or SYSRAC, the account specifically used to manage Oracle Real Application
Clusters, or from Oracle-supplied roles, unless Oracle Support has specifically directed
you to.
- Match common and local scope exactly. If COMMON shows YES in the
relevant DBA_*_PRIVS view, revoke it in the root with CONTAINER=ALL; a common grant
genuinely cannot be revoked locally, confirmed directly in Oracle's own syntax
reference.
- You cannot revoke only ADMIN OPTION or only GRANT OPTION on their own.
Revoke the privilege entirely, then grant it again without the option:
REVOKE CREATE USER FROM security_admin;
GRANT CREATE USER TO security_admin;
REVOKE SELECT ON hr.employees FROM app_owner;
GRANT SELECT ON hr.employees TO app_owner;
There is no REVOKE ADMIN OPTION clause; this two-step sequence is the only supported
way.
- Clean up default roles after revoking a role. Removing a role from
a user doesn't automatically update which roles activate by default at connection:
ALTER USER scott DEFAULT ROLE ALL EXCEPT accts_rec;
-- or
ALTER USER scott DEFAULT ROLE NONE;
- Test in a non-production clone first. Revokes are immediately
disruptive by nature; generate the revoke script, run it in test, and keep a matching
regrant script on hand in case you need to reverse it.
- Watch definer's-rights objects specifically. Revoke a privilege from
a view or procedure's owner, and that object can go invalid, cutting off everyone who
uses it, even users who still hold a perfectly valid grant on the object itself.
- Prefer revoking a role over peeling privileges off individual users.
One role revocation is far easier to reason about, and to reverse, than tracking down
every user who happened to receive a privilege directly.
CDB and PDB Considerations
Since every Oracle AI Database 26ai database is a multitenant container database, scope
matching isn't optional: a local grant is revoked in that specific PDB with
CONTAINER=CURRENT, the default, and a common grant is revoked from the root with
CONTAINER=ALL. A single common user can genuinely hold a mix of both, a common role
alongside local object grants made separately in one PDB, so check COMMON and INHERITED
before assuming either scope applies uniformly.
REVOKE CREATE SESSION FROM c##app CONTAINER = ALL; -- common
REVOKE SELECT ON hr.emp FROM c##app CONTAINER = CURRENT; -- local
Verifying the Revoke Actually Took Effect
SELECT privilege FROM dba_sys_privs WHERE grantee = 'SCOTT';
SELECT granted_role FROM dba_role_privs WHERE grantee = 'SCOTT';
SELECT privilege, schema FROM dba_schema_privs WHERE grantee = 'SCOTT';
SELECT owner, table_name, privilege FROM dba_tab_privs WHERE grantee = 'SCOTT';
Have the affected account reconnect, or re-enable roles explicitly, and rerun whatever
critical path you're concerned about. An existing session keeps whatever roles were
already enabled until it re-enables roles or reconnects entirely; the revoke is real and
immediate at the data dictionary level, but a session's currently active privilege set,
covered in the previous lesson on SESSION_PRIVS, doesn't necessarily refresh until that
session does something to trigger it.
Removing a User Entirely, Compared to Revoking Privileges
Revoking everything a user holds does not remove the account itself. To remove the
account and decide what happens to whatever it owns, DROP USER is the right tool,
covered in depth earlier in this course:
DROP USER username CASCADE;
Without CASCADE, the drop fails outright if the user still owns any objects. With
CASCADE, Oracle drops the user along with their objects and any dependent foreign-key
constraints elsewhere, while views and procedures elsewhere that merely reference those
objects become invalid rather than being dropped themselves, exactly the CASCADE behavior
covered in full detail in this course's user-management module.
Best-Practice Summary
- Prefer roles over direct privileges wherever practical; grant a
role, and revoke by removing the role.
- Apply least privilege consistently, and audit periodically through
DBA_TAB_PRIVS, DBA_SYS_PRIVS, DBA_SCHEMA_PRIVS, and DBA_ROLE_PRIVS rather than relying on
memory of what was granted months ago.
- Stage disruptive changes in non-production first.
- Audit the use of genuinely powerful privileges through unified
auditing, the only auditing mechanism current Oracle releases support for new
configuration, particularly for privileges like ALTER SYSTEM and DROP ANY TABLE.
