Creating dedicated roles in PostgreSQL supports least-privilege access by separating application credentials from administrative accounts, reducing the blast radius of a leaked password or compromised service account.
PostgreSQL models both users and groups as roles, where attributes such as LOGIN control whether a role can authenticate, and role membership allows permissions to be assigned once and reused across multiple accounts. Roles are created and managed with SQL statements such as CREATE ROLE and ALTER ROLE, and privileges are granted at the database, schema, and object levels.
Role creation typically requires superuser-level access (or a role with sufficient privilege) and is commonly performed locally as the operating-system postgres account. Password handling and authentication are influenced by the server’s pg_hba.conf rules, so role credentials alone do not guarantee password-based logins will work from every host. Avoid granting SUPERUSER (or broad privileges) to application roles, and prefer explicit, minimal permissions that can be audited and rotated safely.
Related: How to grant privileges in PostgreSQL \\
Related: How to harden default privileges in PostgreSQL
$ sudo -u postgres psql
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'appuser') THEN
CREATE ROLE appuser LOGIN;
END IF;
END$$;
DO
Use CREATE ROLE appuser LOGIN; when the role does not already exist, or wrap it in a conditional block for repeatable automation.
$ sudo -u postgres psql -c "ALTER ROLE appuser PASSWORD 'S3curePass!2025';" ALTER ROLE
Passwords embedded directly in commands (for example PASSWORD '... ') can be exposed via shell history, process listings, or provisioning logs.
$ sudo -u postgres createdb --owner=appuser appdb
$ sudo -u postgres psql -c "REVOKE CONNECT ON DATABASE appdb FROM PUBLIC;" REVOKE
Revoking CONNECT from PUBLIC blocks all roles without an explicit grant, which can break existing users and automation targeting the same database.
$ sudo -u postgres psql -c "GRANT CONNECT ON DATABASE appdb TO appuser;" GRANT
$ sudo -u postgres psql -c "ALTER ROLE appuser CONNECTION LIMIT 2;" ALTER ROLE
Use CONNECTION LIMIT -1 to remove the limit.
$ sudo -u postgres psql -c "SELECT rolname AS role, rolcanlogin AS can_login, rolsuper AS superuser, rolconnlimit AS conn_limit FROM pg_roles WHERE rolname='appuser';" role | can_login | superuser | conn_limit ---------+-----------+-----------+------------ appuser | t | f | 2 (1 row)
$ sudo -u postgres psql -c "SELECT datname AS database, pg_catalog.pg_get_userbyid(datdba) AS owner FROM pg_database WHERE datname='appdb';" database | owner ----------+-------- appdb | appuser (1 row)