PostgreSQL error 28000
role does not exist
The server has no role (user) with exactly that name. Usually the client sent a name you didn’t choose, such as your Mac user name or root, or the server’s first superuser isn’t called postgres.
FATAL: role "postgres" does not exist
Tested on PostgreSQL 18.6 · Updated 9 October 2026
What it means
PostgreSQL calls users “roles”. This message says the server has no role with the exact name your
client sent. Names are compared exactly, so App and app are different roles.
You see it when you connect through a pg_hba.conf rule that doesn’t ask for a password (trust,
peer, ident or a certificate). Through a password rule, a missing role gets
password authentication failed instead, on
purpose, so strangers can’t find out which names exist. At connection time the SQLSTATE is 28000.
The same words appear as an ERROR inside SQL, when a statement names a role that isn’t there:
GRANT, ALTER ROLE and DROP ROLE give SQLSTATE 42704; SET ROLE gives 22023.
Common causes
- You didn’t give a user name, so the client used your operating-system user name. On a Mac
that’s your login name; in
docker exec, it’sroot. - The first superuser isn’t called
postgres.initdbnames it after the operating-system user who ran it, unless told otherwise. The official Docker image names it afterPOSTGRES_USER, which defaults topostgresbut is often set to something else. - The Docker settings changed after the first start.
POSTGRES_USER,POSTGRES_PASSWORDandPOSTGRES_DBonly take effect when the container starts with an empty data directory. Change them later and the existing volume keeps the old role. - Upper and lower case. A role created as
"App"(in quotes) keeps its capital; unquoted names in SQL are folded to lower case, soSET ROLE Applooks forapp. - A different server. The role exists, but on another install, container or port than the one you reached (a Homebrew server on 5432 and a Docker one on another port, say).
- The role was never restored.
pg_dumpcopies one database, not the roles that own it.
How to fix it
Say which user to connect as
psql -h <host> -U <user> -d <database>
In a URL, the user goes before the @: postgresql://<user>@<host>:5432/<database>. For the
official Docker image:
docker exec -it <container> psql -U <POSTGRES_USER> -d <POSTGRES_DB>
docker exec <container> env | grep POSTGRES_ shows what the container was started with, but not
what an older volume was created with.
List the roles that exist
Connect as any role that works and run:
SELECT rolname, rolcanlogin, rolsuper FROM pg_roles ORDER BY rolname;
In psql, \du shows the same list. Look for a near miss: a different spelling, or a capital letter.
Create the role
As a superuser, or a role with CREATEROLE:
CREATE ROLE app LOGIN PASSWORD '<password>';
LOGIN is what lets a role connect. Without it, connecting fails with
role "app" is not permitted to log in. Then grant it what it needs; see
permission denied.
If you want a postgres role because a tool or tutorial expects one, create it the same way (with
SUPERUSER only if it really needs that), or tell the tool which user to use.
Quote names with capitals
SET ROLE "App";
GRANT SELECT ON orders TO "App";
Better still, create roles in lower case so nobody has to remember the quotes.
Bring roles across with a restore
On the old server, pg_dumpall --roles-only writes CREATE ROLE statements for every role; run them
on the new server before restoring the database dump.
Reproduce it
Our test server runs PostgreSQL 18.6 from the official image with POSTGRES_USER=inlet. Inside
it, the local socket is trusted, so a missing role gets this message. With no -U, psql sends the
container’s user, root:
docker exec inlet-test-pg18-1 psql -d inlet -c 'select 1'
psql: error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: FATAL: role "root" does not exist
The image’s usual superuser name doesn’t exist either, because this container chose another:
docker exec inlet-test-pg18-1 psql -U postgres -d inlet -c 'select 1'
psql: error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: FATAL: role "postgres" does not exist
From the Mac, over TCP with a scram-sha-256 rule, the same kind of name gets the password
message, and only the server log says why:
psql: error: connection to server at "localhost" (::1), port 54318 failed: FATAL: password authentication failed for user "seo_pgconn_nobody"
FATAL: password authentication failed for user "seo_pgconn_nobody"
DETAIL: Role "seo_pgconn_nobody" does not exist.
Inside SQL, with \set VERBOSITY verbose to show the SQLSTATE:
GRANT pg_read_all_data TO seo_pgconn_nobody;
CREATE ROLE "Seo_pgconn_Mixed";
SET ROLE Seo_pgconn_Mixed;
SET ROLE "Seo_pgconn_Mixed";
ERROR: 42704: role "seo_pgconn_nobody" does not exist
LOCATION: get_role_oid, acl.c:5560
CREATE ROLE
ERROR: 22023: role "seo_pgconn_mixed" does not exist
LOCATION: call_string_check_hook, guc.c:6936
SET
The unquoted name was folded to lower case; the quoted one kept its capitals.
In Inlet
The connection window shows the server’s message with a hint for common causes; check the user name field first. Once you’re connected as any working role, Inlet’s roles and grants view shows the server’s roles, so you can check the exact spelling.