InletDownload

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

  1. 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’s root.
  2. The first superuser isn’t called postgres. initdb names it after the operating-system user who ran it, unless told otherwise. The official Docker image names it after POSTGRES_USER, which defaults to postgres but is often set to something else.
  3. The Docker settings changed after the first start. POSTGRES_USER, POSTGRES_PASSWORD and POSTGRES_DB only take effect when the container starts with an empty data directory. Change them later and the existing volume keeps the old role.
  4. Upper and lower case. A role created as "App" (in quotes) keeps its capital; unquoted names in SQL are folded to lower case, so SET ROLE App looks for app.
  5. 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).
  6. The role was never restored. pg_dump copies 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.

Related

Sources