Managing Roles   «Prev  Next»

Lesson 7 The SESSION_PRIVS View
Objective Determine what privileges you have.

SESSION_PRIVS: Privileges Enabled Right Now

This module has now covered granting a privilege, delegating the authority to grant it further, and querying the full data dictionary to see everything that has ever been granted to anyone. This lesson narrows the focus deliberately, to a single, practical question: not what has been granted in the database's entire history, but what is actually usable in this one session, right now, at this exact moment. That distinction turns out to matter a great deal more in practice than it might first appear.
SESSION_PRIVS lists the system privileges currently usable in your session. That phrasing is precise for a reason: this view answers "what can I actually do right now," which turns out to be a genuinely different question from "what have I been granted," and conflating the two is the single most common misunderstanding this lesson needs to clear up.

The Basic Query

SESSION_PRIVS returns information about you specifically; it only makes sense to query it for the session you're actually running it from, since there is no GRANTEE column to filter by someone else:
SELECT * FROM session_privs;
The view has exactly one column, named PRIVILEGE. Older material sometimes shows this as PRIVILEGES, plural; that is not the actual column name. Its definition:
Column      Datatype       Null?     Description
----------- -------------- --------- ------------------------
PRIVILEGE   VARCHAR2(40)   NOT NULL  Name of the privilege
SESSION_PRIVS describes the system privileges currently available to the user, drawing from both direct grants and whatever roles happen to be enabled in the session at the moment the query runs. That second source, enabled roles, is exactly where this view earns its keep, and exactly where it can also mislead you if you don't understand it precisely.

Oracle Autonomous AI Database

A Worked Example, Straight from Oracle's Own Documentation

Rather than an arbitrary list of privileges, it's worth working through Oracle's own official example for this exact view, since it demonstrates the role-enablement behavior far more precisely than a static list ever could. Assume the following setup already exists:
CREATE ROLE security_admin IDENTIFIED BY password;

GRANT CREATE PROFILE, ALTER PROFILE, DROP PROFILE,
    CREATE ROLE, DROP ANY ROLE, GRANT ANY ROLE, AUDIT ANY,
    AUDIT SYSTEM, CREATE USER, BECOME USER, ALTER USER, DROP USER
    TO security_admin WITH ADMIN OPTION;

GRANT security_admin, CREATE SESSION TO swilliams;
User swilliams now holds the security_admin role, carrying a substantial set of administrative privileges, plus a direct CREATE SESSION grant of her own.
First, confirm which roles are actually enabled right now with SESSION_ROLES, a companion view worth introducing alongside SESSION_PRIVS since the two are documented together and answer closely related questions:
SELECT * FROM session_roles;
If swilliams has security_admin enabled in this session, the result is:
ROLE
------------------------------
SECURITY_ADMIN
Now query SESSION_PRIVS in that same session:
SELECT * FROM session_privs;

PRIVILEGE
----------------------------------------
AUDIT SYSTEM
CREATE SESSION
CREATE USER
BECOME USER
ALTER USER
DROP USER
CREATE ROLE
DROP ANY ROLE
GRANT ANY ROLE
AUDIT ANY
CREATE PROFILE
ALTER PROFILE
DROP PROFILE
CREATE SESSION appears because it was granted directly. Everything else in this list traces back to the security_admin role being currently enabled, not to any direct grant on swilliams's own account.

What Happens When the Role Is Disabled

This is the detail that makes SESSION_PRIVS genuinely different from a simple "what have I been granted" view, and it is worth stating precisely rather than approximately: if the security_admin role is disabled for swilliams, SESSION_ROLES returns no rows at all, and SESSION_PRIVS returns only a single row, CREATE SESSION. Every privilege that traced back to the role simply disappears from the result the moment the role itself is no longer enabled, even though swilliams still holds that role in the sense that DBA_ROLE_PRIVS and USER_ROLE_PRIVS would still show it granted to her. Nothing has been revoked; the privileges granted through the role are simply not currently active in this session.
This is precisely why SESSION_PRIVS is the right view for answering "can I do this right now" and the wrong view for answering "what have I ever been granted." A privilege can be completely real, fully granted, and entirely invisible to SESSION_PRIVS at the same time, if the role carrying it isn't currently switched on.

What SESSION_PRIVS Does Not Show

SESSION_PRIVS is scoped narrowly to system privileges, and it's worth knowing exactly where to look for everything it deliberately leaves out:
Kind of access Where to look instead
Object privileges, such as SELECT on hr.employees USER_TAB_PRIVS, ALL_TAB_PRIVS, ROLE_TAB_PRIVS
Schema privileges, such as SELECT ANY TABLE ON SCHEMA hr SESSION_SCHEMA_PRIVS or SESSION_PRIVS_ALL
Which roles are actually enabled right now SESSION_ROLES
Grants that exist but aren't currently enabled USER_SYS_PRIVS, USER_ROLE_PRIVS
The distinction between object privileges and system privileges is worth restating plainly, since it trips people up constantly: holding CREATE TABLE in SESSION_PRIVS says nothing at all about whether you can SELECT from a specific table someone else owns. Object access is an entirely separate grant, tracked in an entirely separate set of views, covered in the previous lesson's tour of the full privilege dictionary.
ROLE_TAB_PRIVS in particular deserves a moment of its own attention, since its scope is easy to misjudge. It describes table privileges granted specifically to roles, not to users directly, and it reports information only about roles the current user actually has enabled, not every role in the database. This makes it a genuinely useful companion to SESSION_ROLES: once you know which roles are active in your session, ROLE_TAB_PRIVS is where you go to see exactly what object-level access those specific roles carry, rather than working backward from a table you're curious about and hoping to guess which role might be responsible for your access to it.

SESSION_PRIVS_ALL: Adding Schema Privileges

Current Oracle releases add SESSION_PRIVS_ALL alongside the classic SESSION_PRIVS, covering system privileges and schema-level privileges together in a single view:
SELECT privilege, schema FROM session_privs_all;
The SCHEMA column works the same way here as it does throughout the rest of this project's coverage of the newer _ALL views: it is null for an ordinary system privilege, and populated with a schema name for a schema-level grant currently active in the session. Querying SESSION_PRIVS_ALL instead of the classic SESSION_PRIVS is the right move the moment you need to know about schema-level access alongside system privileges in one pass, rather than checking two views separately and combining the results yourself.

Roles Inside PL/SQL: A Case Where SESSION_PRIVS Can Actively Mislead You

There is one scenario worth understanding in real depth, because it produces exactly the kind of confusing failure this lesson exists to help you diagnose: a privilege shows up in SESSION_PRIVS for your interactive session, yet a stored procedure you run still fails with an insufficient-privileges error. This isn't a bug or an inconsistency; it's Oracle's role behavior working precisely as designed, once you know the rule.
How roles behave inside a PL/SQL block depends entirely on whether that block runs with definer's rights or invoker's rights:
  • Named blocks with definer's rights, the default for stored procedures, functions, and triggers, disable every role entirely. Roles play no part in privilege checking inside such a block, and you cannot even issue a SET ROLE statement from within one. If a definer's-rights procedure itself queries SESSION_ROLES, the query returns no rows at all, regardless of what roles are enabled in the session that called it.
  • Named blocks with invoker's rights, and anonymous PL/SQL blocks, behave the way you'd naturally expect: whatever roles are currently enabled in the calling session are used for privilege checking inside the block too, the same roles SESSION_PRIVS and SESSION_ROLES would already show you.
The practical consequence is significant: a definer's-rights procedure can only use privileges granted directly to its owner, never privileges the owner holds only through a role. If security_admin's procedures need CREATE USER, that privilege has to be granted to security_admin directly, not merely inherited through some other role, or any definer's-rights procedure security_admin writes that needs it will fail regardless of what SESSION_PRIVS shows for the interactive session. This is exactly the kind of gotcha worth checking first the moment a procedure fails with a privilege error despite the account clearly having the privilege interactively: check whether the failing code runs with definer's rights, and if so, check whether the privilege in question was actually granted directly rather than through a role.
The practical consequence is significant: a definer's-rights procedure can only use privileges granted directly to its owner, never privileges the owner holds only through a role. If security_admin's procedures need CREATE USER, that privilege has to be granted to security_admin directly, not merely inherited through some other role, or any definer's-rights procedure security_admin writes that needs it will fail regardless of what SESSION_PRIVS shows for the interactive session. This is exactly the kind of gotcha worth checking first the moment a procedure fails with a privilege error despite the account clearly having the privilege interactively: check whether the failing code runs with definer's rights, and if so, check whether the privilege in question was actually granted directly rather than through a role.
It's worth being precise about why Oracle designed it this way, since the restriction can otherwise feel arbitrary. Definer's rights procedures execute with the privileges of whoever created them, not whoever calls them, which is exactly what makes them useful for controlled access: an application user with very limited direct privileges can still run a definer's-rights procedure that performs privileged operations on their behalf, as long as the procedure's owner holds the necessary privileges. If role-based privileges were honored inside such a procedure, a user could potentially gain broader access simply by having a role enabled at the moment they happened to invoke the procedure, an unstable and hard-to-audit basis for a security boundary. Disabling roles inside definer's-rights code removes that instability entirely: the procedure's privilege set becomes fixed and predictable, determined solely by what its owner was granted directly, not by whatever happened to be enabled in whoever called it.
This also explains why anonymous PL/SQL blocks and invoker's-rights procedures behave differently, and why that difference is deliberate rather than an oversight. An anonymous block, the kind you type directly at a SQL*Plus prompt inside a BEGIN...END, executes as an extension of your own session; there is no separate owner to speak of, so using your own currently enabled roles is the only sensible behavior. An invoker's-rights procedure makes the same choice deliberately, running with the privileges of whoever calls it rather than whoever wrote it, which is exactly the situation where honoring the caller's enabled roles is the correct, intended behavior rather than a security gap.

SESSION_ROLES in More Depth

SESSION_ROLES, already introduced above alongside SESSION_PRIVS, deserves its own brief treatment given how tightly the two are linked. Its single column, ROLE, lists every role currently enabled for the session, the same set of roles SESSION_PRIVS is effectively summarizing into individual privileges. A role can be simultaneously enabled for one user and disabled for another at the very same time, since enablement is a per-session state, not a property of the role itself. Querying SESSION_ROLES first, before SESSION_PRIVS, is often the faster diagnostic step: if a role you expect is missing from SESSION_ROLES entirely, there's no need to comb through SESSION_PRIVS looking for privileges that role would have carried, since none of them can possibly be present.

A Worked Example of SESSION_PRIVS_ALL

Suppose swilliams also holds a schema-level privilege, SELECT ANY TABLE ON SCHEMA hr, alongside everything already granted through security_admin. Querying the classic SESSION_PRIVS would show only her system privileges, with the schema-level grant nowhere in the result at all. SESSION_PRIVS_ALL closes that gap:
SELECT privilege, schema FROM session_privs_all;

PRIVILEGE                    SCHEMA
----------------------------- --------
AUDIT SYSTEM
CREATE SESSION
CREATE USER
BECOME USER
ALTER USER
DROP USER
SELECT ANY TABLE              HR
Every row with a blank SCHEMA value is an ordinary system privilege, active session-wide. The one row with HR in the SCHEMA column is the schema-level grant, active only within that specific schema. A single query now answers a question that used to require checking two separate views and mentally merging the results.

Putting This in Practical Terms

SESSION_PRIVS answers one question well: which system privileges can I exercise at this exact moment. It does not answer, and was never meant to answer, the broader question of everything you have ever been granted, and it says nothing whatsoever about object-level access to a specific table, view, or other object. If a script or an application suddenly fails with a privilege error despite you being certain the underlying grant exists, work through the investigation in a specific order rather than guessing: confirm what SESSION_ROLES shows as currently enabled, confirm what SESSION_PRIVS shows as currently active, then compare that against what USER_ROLE_PRIVS or DBA_ROLE_PRIVS shows as actually granted. A gap between the two almost always means one of two things: either a role exists but isn't currently switched on, or the failing code runs with definer's rights and needs a direct grant rather than a role-derived one.
Between SESSION_PRIVS for the classic system-privilege picture, SESSION_PRIVS_ALL for system and schema privileges together, and SESSION_ROLES for the roles underlying both, you have a precise, reliable way to answer exactly what a session, or a piece of code running inside it, can actually do right now. That's a genuinely different and often more immediately useful question than the fuller historical picture DBA_SYS_PRIVS and DBA_ROLE_PRIVS provide about everything that has ever been granted, and knowing which of the two questions you're actually asking is most of the battle the next time something fails for reasons that aren't immediately obvious.
SEMrush Software 7 SEMrush Banner 7