REVOKE(7)
๐ REVOKE ๐
okay so bestie, welcome to REVOKE(7) โ the PostgreSQL 18.6 manual page that teaches you how to take privileges back. yes, we're doing subtraction today. it's giving "you can't sit with us anymore" but make it SQL. ๐
โจ NAME โจ
REVOKE โ remove access privileges
๐ธ SYNOPSIS ๐ธ
REVOKE [ GRANT OPTION FOR ]
{ { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER | MAINTAIN }
[, ...] | ALL [ PRIVILEGES ] }
ON { [ TABLE ] table_name [, ...]
| ALL TABLES IN SCHEMA schema_name [, ...] }
FROM role_specification [, ...]
[ GRANTED BY role_specification ]
[ CASCADE | RESTRICT ]
REVOKE [ GRANT OPTION FOR ]
{ { SELECT | INSERT | UPDATE | REFERENCES } ( column_name [, ...] )
[, ...] | ALL [ PRIVILEGES ] ( column_name [, ...] ) }
ON [ TABLE ] table_name [, ...]
FROM role_specification [, ...]
[ GRANTED BY role_specification ]
[ CASCADE | RESTRICT ]
REVOKE [ GRANT OPTION FOR ]
{ { USAGE | SELECT | UPDATE }
[, ...] | ALL [ PRIVILEGES ] }
ON { SEQUENCE sequence_name [, ...]
| ALL SEQUENCES IN SCHEMA schema_name [, ...] }
FROM role_specification [, ...]
[ GRANTED BY role_specification ]
[ CASCADE | RESTRICT ]
REVOKE [ GRANT OPTION FOR ]
{ { CREATE | CONNECT | TEMPORARY | TEMP } [, ...] | ALL [ PRIVILEGES ] }
ON DATABASE database_name [, ...]
FROM role_specification [, ...]
[ GRANTED BY role_specification ]
[ CASCADE | RESTRICT ]
REVOKE [ GRANT OPTION FOR ]
{ USAGE | ALL [ PRIVILEGES ] }
ON DOMAIN domain_name [, ...]
FROM role_specification [, ...]
[ GRANTED BY role_specification ]
[ CASCADE | RESTRICT ]
REVOKE [ GRANT OPTION FOR ]
{ USAGE | ALL [ PRIVILEGES ] }
ON FOREIGN DATA WRAPPER fdw_name [, ...]
FROM role_specification [, ...]
[ GRANTED BY role_specification ]
[ CASCADE | RESTRICT ]
REVOKE [ GRANT OPTION FOR ]
{ USAGE | ALL [ PRIVILEGES ] }
ON FOREIGN SERVER server_name [, ...]
FROM role_specification [, ...]
[ GRANTED BY role_specification ]
[ CASCADE | RESTRICT ]
REVOKE [ GRANT OPTION FOR ]
{ EXECUTE | ALL [ PRIVILEGES ] }
ON { { FUNCTION | PROCEDURE | ROUTINE } function_name [ ( [ [ argmode ] [ arg_name ] arg_type [, ...] ] ) ] [, ...]
| ALL { FUNCTIONS | PROCEDURES | ROUTINES } IN SCHEMA schema_name [, ...] }
FROM role_specification [, ...]
[ GRANTED BY role_specification ]
[ CASCADE | RESTRICT ]
REVOKE [ GRANT OPTION FOR ]
{ USAGE | ALL [ PRIVILEGES ] }
ON LANGUAGE lang_name [, ...]
FROM role_specification [, ...]
[ GRANTED BY role_specification ]
[ CASCADE | RESTRICT ]
REVOKE [ GRANT OPTION FOR ]
{ { SELECT | UPDATE } [, ...] | ALL [ PRIVILEGES ] }
ON LARGE OBJECT loid [, ...]
FROM role_specification [, ...]
[ GRANTED BY role_specification ]
[ CASCADE | RESTRICT ]
REVOKE [ GRANT OPTION FOR ]
{ { SET | ALTER SYSTEM } [, ...] | ALL [ PRIVILEGES ] }
ON PARAMETER configuration_parameter [, ...]
FROM role_specification [, ...]
[ GRANTED BY role_specification ]
[ CASCADE | RESTRICT ]
REVOKE [ GRANT OPTION FOR ]
{ { CREATE | USAGE } [, ...] | ALL [ PRIVILEGES ] }
ON SCHEMA schema_name [, ...]
FROM role_specification [, ...]
[ GRANTED BY role_specification ]
[ CASCADE | RESTRICT ]
REVOKE [ GRANT OPTION FOR ]
{ CREATE | ALL [ PRIVILEGES ] }
ON TABLESPACE tablespace_name [, ...]
FROM role_specification [, ...]
[ GRANTED BY role_specification ]
[ CASCADE | RESTRICT ]
REVOKE [ GRANT OPTION FOR ]
{ USAGE | ALL [ PRIVILEGES ] }
ON TYPE type_name [, ...]
FROM role_specification [, ...]
[ GRANTED BY role_specification ]
[ CASCADE | RESTRICT ]
REVOKE [ { ADMIN | INHERIT | SET } OPTION FOR ]
role_name [, ...] FROM role_specification [, ...]
[ GRANTED BY role_specification ]
[ CASCADE | RESTRICT ]
and role_specification can be literally any of these:
[ GROUP ] role_name
| PUBLIC
| CURRENT_ROLE
| CURRENT_USER
| SESSION_USER
like. that's the whole menu. iconic ๐
๐ฆ DESCRIPTION ๐ฆ
REVOKE takes privileges that were previously granted and yeets them back out of existence for one or more roles. the keyword PUBLIC is doing a lot of heavy lifting here โ it refers to that implicitly defined group of every single role ever. the whole squad. ๐ซถ
for what each privilege type actually means, go read the description of the GRANT command, bestie. that's its job, not mine. โจ
okay now the important part, the lore, the plot twist: any particular role has the sum of:
- privileges granted directly to it
- privileges granted to any role it is presently a member of
- privileges granted to
PUBLIC
so likeโฆ if you revoke SELECT from PUBLIC, that does not automatically mean every role lost SELECT on that object. the ones who have it granted directly, or via another role, still have it. same energy the other direction: revoking SELECT from one user might not stop that user from using SELECT if PUBLIC or some other role they're a member of still has SELECT rights. privileges stack, babes. no cap. ๐
if GRANT OPTION FOR is specified, only the grant option for the privilege gets revoked โ not the privilege itself. otherwise, both the privilege and the grant option go bye-bye. โ๏ธ
now, if a user holds a privilege with grant option and has passed it on to other users, the privileges those other users hold are called dependent privileges. if the privilege or grant option held by that first user is being revoked and dependent privileges exist, then:
- with
CASCADEโ those dependent privileges get revoked too ๐ฅ - without it โ the revoke action fails. periodt. ๐
this recursive revocation only touches privileges that were granted through a chain of users traceable back to the user who is the subject of this REVOKE command. so the affected users might effectively keep the privilege anyway if it was also granted through other users. sneaky but valid. ๐ง
when you revoke privileges on a table, the corresponding column privileges (if there are any) are automatically revoked on each column of the table too. on the other hand, if a role has been granted privileges on a table, then revoking the same privileges from individual columns will have no effect. literally nothing. nothing happens. ๐
when you're revoking membership in a role, GRANT OPTION is instead called ADMIN OPTION, but the behavior is similar. note that in releases prior to PostgreSQL 16, dependent privileges were not tracked for grants of role membership, and thus CASCADE had no effect for role membership. this is no longer the case. also note that this form of the command does not allow the noise word GROUP in role_specification. ๐ซ
and just like ADMIN OPTION can be removed from an existing role grant, you can also revoke INHERIT OPTION or SET OPTION. this is equivalent to setting the value of the corresponding option to FALSE. ๐
๐ NOTES ๐
a user can only revoke privileges that were granted directly by that user. example time, bestie:
- user A grants a privilege with grant option to user B
- user B grants it on to user C
- user A cannot revoke the privilege directly from C ๐ญ
instead, user A could revoke the grant option from user B and use the CASCADE option so the privilege is in turn revoked from C. ๐ฏ
another example: if both A and B have granted the same privilege to C, A can revoke their own grant but not B's grant โ so C will still effectively have the privilege. sorry A. ๐ฅฒ
when a non-owner of an object attempts to REVOKE privileges on it, the command fails outright if the user has no privileges whatsoever on the object. as long as some privilege is available, the command proceeds, but it will revoke only those privileges for which the user has grant options. the REVOKE ALL PRIVILEGES forms will issue a warning message if no grant options are held, while the other forms will issue a warning if grant options for any of the privileges specifically named in the command are not held. (in principle these statements apply to the object owner as well, but since the owner is always treated as holding all grant options, the cases can never occur.) ๐
if a superuser chooses to issue a GRANT or REVOKE command, the command is performed as though it were issued by the owner of the affected object. (since roles do not have owners, in the case of a GRANT of role membership, the command is performed as though it were issued by the bootstrap superuser.) since all privileges ultimately come from the object owner โ possibly indirectly via chains of grant options โ it is possible for a superuser to revoke all privileges, but this might require use of CASCADE as stated above. โก
REVOKE can also be done by a role that is not the owner of the affected object, but is a member of the role that owns the object, or is a member of a role that holds privileges WITH GRANT OPTION on the object. in this case the command is performed as though it were issued by the containing role that actually owns the object or holds the privileges WITH GRANT OPTION. for example, if table t1 is owned by role g1, of which role u1 is a member, then u1 can revoke privileges on t1 that are recorded as being granted by g1. this would include grants made by u1 as well as by other members of role g1. ๐ซ
if the role executingREVOKEholds privileges indirectly via more than one role membership path, it is unspecified which containing role will be used to perform the command. in such cases it is best practice to useSET ROLEto become the specific role you want to do theREVOKEas. failure to do so might lead to revoking privileges other than the ones you intended, or not revoking anything at all. ๐ be careful bestie, this one bites.
see Section 5.8 for more information about specific privilege types, as well as how to inspect objects' privileges. ๐
๐ EXAMPLES ๐
revoke insert privilege for the public on table films:
REVOKE INSERT ON films FROM PUBLIC;
revoke all privileges from user manuel on view kinds:
REVOKE ALL PRIVILEGES ON kinds FROM manuel;
note that this actually means โrevoke all privileges that I grantedโ. ๐ซถ
revoke membership in role admins from user joe:
REVOKE admins FROM joe;
โญ COMPATIBILITY โญ
the compatibility notes of the GRANT command apply analogously to REVOKE. the keyword RESTRICT or CASCADE is required according to the standard, but PostgreSQL assumes RESTRICT by default. ๐ซ
๐ฅ SEE ALSO ๐ฅ
GRANT(7)ALTER DEFAULT PRIVILEGES(ALTER_DEFAULT_PRIVILEGES(7))
and that's the whole page, bestie!! ๐โจ๐ธ this was PostgreSQL 18.6, dated 2026, and it lives at page REVOKE(7) โ go forth and un-grant responsibly, mwah ๐๐
๐
๐ฆ where this page comes from
- opensuse-leap 16.0: postgresql18 18.6-160000.1.1 ยท PostgreSQL
- opensuse-leap 16.0: postgresql18 18.6-160000.1.1 ยท PostgreSQL
- opensuse-leap 16.0: postgresql18 18.6-160000.1.1 ยท PostgreSQL
- opensuse-leap 16.0: postgresql18 18.6-160000.1.1 ยท PostgreSQL
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms