Essential Commands for Managing Users, Roles, and Permissions in PostgreSQL
Manage PostgreSQL roles, group membership, grants, revokes, default privileges, and permission audits with practical SQL examples.
Essential Commands for Managing Users, Roles, and Permissions in PostgreSQL
PostgreSQL users, roles, and permissions decide who can connect, what they can read, and what they can change. If those permissions grow by guesswork, your database becomes hard to audit and easy to overexpose.
PostgreSQL uses one concept, the role, for both login users and groups. A role with LOGIN can connect. A role without LOGIN is often used as a group that carries shared privileges.
Create and Change Roles
Create an application login role with a password:
CREATE ROLE app_user WITH LOGIN PASSWORD 'strong_password_here';
Create a group role for shared read access:
CREATE ROLE reporting_readonly NOLOGIN;
Common role attributes include:
| Attribute | What it allows |
|---|---|
LOGIN |
Connect to the database server. |
CREATEDB |
Create databases. |
CREATEROLE |
Create, alter, and drop many roles, with important limits around superuser roles. |
REPLICATION |
Use replication connections. |
SUPERUSER |
Bypass normal permission checks. Use only for tightly controlled admin roles. |
INHERIT |
Use privileges from roles it is a member of. This is the default. |
Change a password or disable login with ALTER ROLE:
ALTER ROLE app_user WITH PASSWORD 'new_strong_password';
ALTER ROLE old_employee NOLOGIN;
Before dropping a role, handle anything it owns and any privileges it has been granted:
REASSIGN OWNED BY old_employee TO postgres;
DROP OWNED BY old_employee;
DROP ROLE old_employee;
REASSIGN OWNED transfers owned objects. DROP OWNED removes privileges granted to the role and can drop objects still owned by it in the current database, so review carefully before running it.
Use Group Roles for Cleaner Access
Grant permissions to group roles, then add people or application roles to those groups.
GRANT reporting_readonly TO alice, bob;
REVOKE reporting_readonly FROM bob;
WITH ADMIN OPTION lets the member grant and revoke that role membership for others. It does not by itself make the member a superuser or give unrestricted power over the database.
GRANT reporting_readonly TO team_lead WITH ADMIN OPTION;
This pattern keeps access easier to audit. Instead of checking 50 users for table grants, you can check the group role.
Grant Object Permissions
Use GRANT to allow specific actions on specific objects.
GRANT SELECT ON TABLE production.orders TO reporting_readonly;
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE app.orders TO app_user;
Common table privileges are SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, and TRIGGER.
Schema permissions are separate from table permissions. A role often needs USAGE on the schema and privileges on the tables inside it:
GRANT USAGE ON SCHEMA app TO app_user;
GRANT SELECT ON ALL TABLES IN SCHEMA app TO app_user;
For inserts that use sequences, grant sequence access too:
GRANT USAGE, SELECT ON SEQUENCE app.orders_id_seq TO app_user;
For functions, grant execution explicitly:
GRANT EXECUTE ON FUNCTION app.audit_log_insert(text) TO app_user;
Revoke Permissions
REVOKE removes a direct grant.
REVOKE INSERT ON TABLE production.orders FROM app_user;
REVOKE ALL PRIVILEGES ON TABLE production.orders FROM reporting_readonly;
If a user still has access after a revoke, check group membership. The user may inherit the same privilege through another role.
Set Permissions for Future Tables
GRANT ON ALL TABLES affects existing tables only. For tables created later, use ALTER DEFAULT PRIVILEGES from the role that will create those tables.
ALTER DEFAULT PRIVILEGES FOR ROLE app_owner IN SCHEMA app
GRANT SELECT ON TABLES TO reporting_readonly;
This is one of the most common missing steps in PostgreSQL permission setups. A user can read today's tables but gets denied on tomorrow's table because default privileges were never configured.
Audit Current Access
In psql, these commands are fast checks:
\du
\du+ app_user
\dp app.orders
\dn+
Catalog views are better for repeatable reports:
SELECT rolname, rolsuper, rolcreaterole, rolcreatedb, rolcanlogin
FROM pg_roles
ORDER BY rolname;
For table grants:
SELECT grantee, table_schema, table_name, privilege_type
FROM information_schema.table_privileges
WHERE table_schema = 'app'
ORDER BY grantee, table_name, privilege_type;
Security Habits That Pay Off
Give applications dedicated roles instead of using a human DBA account. Grant the smallest set of privileges the application needs. Avoid SUPERUSER and broad ALL PRIVILEGES grants for day-to-day work.
Use group roles for shared access, and review memberships regularly. When someone changes teams, removing one group membership is safer than hunting down table-level grants.
The practical next step is to pick one production schema and list its roles, memberships, table grants, and default privileges. Fix the gaps there before expanding the same pattern to the rest of your databases.