FATAL: role "app" does not exist means the user name you connected with is
not a role on that server. PostgreSQL users are roles, and the official Docker image
creates exactly one of them; any other name has to be created with
CREATE ROLE ... LOGIN before it can connect.
Connect once as the superuser the image made (postgres unless you set
POSTGRES_USER), run CREATE ROLE app LOGIN PASSWORD '...', then
connect as app and name a database that exists.
The error
docker exec fix4-pg18 psql -U app
psql: error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: FATAL: role "app" does not exist
psql does not print the SQLSTATE for a failed connection. With
log_error_verbosity = verbose the server log shows it:
FATAL: 28000: role "app" does not exist
LOCATION: InitializeSessionUserId, miscinit.c:802
Why it happens
PostgreSQL has no separate list of users. A user is a role with the LOGIN
attribute, and the server checks the name you pass with -U (or
Username= in a connection string) against that list before it looks at any
password. Code 28000 is "invalid authorization specification": the server stopped at the
name, so changing the password will not help.
The postgres Docker image runs initdb with one superuser, named
by POSTGRES_USER and defaulting to postgres. A connection string
copied from another project, or an appsettings.json that says
Username=app, points at a role this fresh server has never heard of. The
variable is also read only when the data directory is empty, so setting it on a container
that already has a volume does not create the role either.
The fix
docker exec fix4-pg18 psql -U postgres -c "CREATE ROLE app LOGIN PASSWORD 'change-me-123'"
CREATE ROLE
docker exec -e PGPASSWORD=change-me-123 fix4-pg18 psql -h localhost -U app -d postgres -c "SELECT current_user, current_database()"
current_user | current_database
--------------+------------------
app | postgres
(1 row)
fix4-pg18 and the password are the test's own; use your container name and a
real secret. Note the -d postgres: straight after the role existed,
psql -U app on its own failed again with
FATAL: database "app" does not exist, because psql uses the user name as the
database name when you give none. Name an existing database, or create one and make the
new role its owner with CREATE DATABASE appdb OWNER app. The alternative is
to recreate the container with POSTGRES_USER=app on an empty volume, which
makes app the superuser; fine for a throwaway dev box, too much power for an
application account.
How it was reproduced
A fresh postgres:18 container (PostgreSQL 18.4, Debian build) on Docker
Desktop 4.91.0 under Windows 11, started with only POSTGRES_PASSWORD set and
published on port 15460. Running psql -U app inside it produced the error
above; the server log line came from the same attempt after
ALTER SYSTEM SET log_error_verbosity = verbose and a reload. The
CREATE ROLE and the TCP login were run straight after, with the output shown.
Frequently asked
- How do I create a user in PostgreSQL?
- Connect as a superuser and run CREATE ROLE name LOGIN PASSWORD 'secret'. CREATE USER does the same thing with LOGIN implied. A role without LOGIN cannot connect at all.
- Why does PostgreSQL in Docker only have the postgres user?
- The official image runs initdb with a single superuser named by POSTGRES_USER, which defaults to postgres. Any other role has to be created afterwards, or by a script in /docker-entrypoint-initdb.d on first start.
- Does setting POSTGRES_USER on an existing container create the role?
- No. The image reads POSTGRES_USER, POSTGRES_PASSWORD and POSTGRES_DB only when the data directory is empty. On a container with existing data, create the role with CREATE ROLE instead.
More decoded errors in the Fixes category. If the role exists and the server says the password is wrong instead, see password authentication failed for user "postgres".