FATAL: role "<name>" does not exist (SQLSTATE 42704, condition undefined_object) is raised when a client tries to authenticate as a PostgreSQL role that has no entry in the cluster's role catalog (pg_authid / pg_roles). The same error appears at SQL level - ERROR: role "<name>" does not exist - when a GRANT, ALTER ROLE, SET ROLE, or ownership statement names a missing role. In both cases the role name is not present in this PostgreSQL cluster.
What This Error Means
PostgreSQL stores all login and group identities as rows in pg_authid. The catalog is cluster-wide, not per-database: a role created in one database is visible from every database in the same cluster. The error appears in two contexts. At connection time, the authentication code checks the supplied user against pg_authid before evaluating pg_hba.conf - a missing role produces a FATAL and the client never sees a session. At runtime, SQL statements that reference a role name (GRANT ... TO, ALTER TABLE ... OWNER TO, SET ROLE) raise 42704 and abort.
Role names follow the same identifier rules as table names: case-folded to lowercase unless double-quoted at creation. A role created with CREATE ROLE "MyApp" is invisible to psql -U myapp and vice versa.
Common Causes
- The role was never created in this cluster - confirm with
SELECT rolname FROM pg_roles WHERE rolname = '<name>';. - Peer authentication is in use and the OS username has no matching Postgres role - check the
locallines inpg_hba.conf. - Wrong cluster targeted - a second PostgreSQL instance on a different port has its own role catalog. Verify with
pg_lsclustersorSHOW port;. - Case-folded mismatch: role created as
"AdminUser"but client connects asadminuser- checkpg_rolesfor the exact spelling. - Role was dropped or expired (
VALID UNTILin the past) - checkrolvaliduntilinpg_roles. - Restored a single database with
pg_restorewithout first restoring globals - role definitions live inpg_dumpall -goutput, not per-database dumps. - Application using a stale connection string after a role rename.
How to Fix role does not exist
Confirm whether the role exists in the cluster. Connect as a superuser and check the catalog:
SELECT rolname, rolcanlogin, rolvaliduntil FROM pg_roles WHERE rolname ILIKE '<name>';If the row is missing, the role has never been created in this cluster.
Create the missing login role.
CREATE USERis shorthand forCREATE ROLE ... LOGIN:CREATE ROLE app_user LOGIN PASSWORD '<strong-password>'; GRANT CONNECT ON DATABASE mydb TO app_user; GRANT USAGE ON SCHEMA public TO app_user;Fix peer authentication mismatches. For local connections using
peer, the OS user must have a matching PostgreSQL role:sudo -u postgres createuser --pwprompt $(whoami)Or change the auth method in
pg_hba.conf:# TYPE DATABASE USER ADDRESS METHOD local all all scram-sha-256Then
sudo systemctl reload postgresql.Verify you are connected to the right cluster. Multiple Postgres instances on one host each have their own role catalog:
pg_lsclusters sudo -u postgres psql -p 5433 -c '\du'Match the exact case if the role was quoted at creation. Double-quote the role name in the connection string and in SQL:
psql "postgresql://AdminUser@localhost/mydb"GRANT pg_read_all_data TO "AdminUser";Restore globals when migrating a cluster. A per-database
pg_restoredoes not include roles. Usepg_dumpall --globals-onlyto capture and replay role definitions:pg_dumpall -h source --globals-only > globals.sql psql -h target -f globals.sqlReset an expired role. Setting
VALID UNTIL 'infinity'or a future date re-enables the role:ALTER ROLE app_user VALID UNTIL 'infinity';
Catch role does not exist Errors Before They Hit Production
Pulse provides AI-powered observability for PostgreSQL alongside Elasticsearch, ClickHouse, and Kafka. For SQLSTATE 42704 undefined_object errors on role lookups, Pulse:
- Tracks
FATAL: role "..." does not existevents in the server log alongsidepg_stat_activityconnection attempts, grouped by role and client IP, so a credential rotation that missed one application instance is immediately visible - Correlates the error with recent role/grant changes,
pg_hba.confreloads, and application deploys so root cause maps to the specific change (aDROP ROLEahead of dependent grants, a renamed role, apeerauth line that no longer matches the OS user) instead of a generic auth failure - Flags role and grant drift across replicas, standby clusters, and environments - a
pg_restorethat skippedpg_dumpall --globals-onlyleaves a cluster with no roles, which Pulse surfaces before the first connection attempt fails
Set log_connections = on so every failed authentication lands in the log, then alert on any non-zero rate of 42704.
Connect your Postgres cluster to surface issues like this proactively.
Preventive Measures
- Manage roles through migrations or a config-management tool (Terraform
postgresql_role, Ansiblepostgresql_user) so role state matches code. - Avoid quoted mixed-case role names. Stick to lowercase; the case-sensitivity surprise is not worth the cosmetics.
- Use
pg_dumpall --globals-onlyin your backup schedule so restores include roles, not just data. - Document role creation and rotation in the runbook for the database, including the exact SQL.
Frequently Asked Questions
Q: What is SQLSTATE 42704 in PostgreSQL?
A: 42704 is the undefined_object SQLSTATE. PostgreSQL raises it when a SQL statement references a database object (role, type, collation, or operator) that does not exist. For roles specifically, the message is role "<name>" does not exist.
Q: Why does psql work as postgres but fail as my own user?
A: Local connections almost always use peer authentication, which maps to the OS user. If your OS account has no matching PostgreSQL role, the lookup fails. Create the role with sudo -u postgres createuser $(whoami), or change the local auth method to scram-sha-256.
Q: What is the difference between a user and a role in PostgreSQL?
A: They are the same database object. CREATE USER is an alias for CREATE ROLE ... LOGIN. A role without LOGIN behaves as a group; roles with LOGIN can authenticate.
Q: Can a role exist in one database but not another?
A: No. Roles are cluster-wide. Once created, a role is visible from every database in the same PostgreSQL cluster. Permissions per database are separate, but the role identity is shared.
Q: How do I rename a role without breaking dependent objects?
A: Use ALTER ROLE old_name RENAME TO new_name;. Object ownership and grants follow the rename automatically because they reference the role's OID, not its name. Update connection strings in applications after the rename.
Q: Why is my role rejected even though I just created it?
A: Two common causes: the role was created without LOGIN (so it cannot authenticate; add ALTER ROLE name LOGIN), or pg_hba.conf has no matching line for the (database, user, address) tuple, producing a different error. Tail the server log to see which.
Q: How can I detect PostgreSQL role does not exist errors before they break the application?
A: Enable log_connections and treat the 42704 rate as an SLI. Pulse aggregates FATAL: role "..." does not exist events by role and client IP, correlates spikes with credential rotations and pg_hba.conf reloads, and flags role drift across replicas - so a missed application instance after a rotation surfaces before it turns into a customer-visible outage.
Related Reading
- PostgreSQL Could Not Connect to Server: connection-time failures before authentication.
- PostgreSQL Connection Refused: TCP-level connection problems.
- PostgreSQL Relation Does Not Exist: the matching error for missing tables and views.
- PostgreSQL Connection String: how the user, host, port, and database are parsed.
- Common PostgreSQL Errors: index of SQLSTATE codes and conditions.
- PostgreSQL Connection Pooling with PgBouncer: pooler-specific authentication considerations.