Immich Won't Start: Postgres Error 28P01 With a "Healthy" Database
Immich refuses to connect, its logs show Postgres error code 28P01, and yet every health check tells you the database is fine. The gist: the password Immich is using to log into Postgres doesn't match the password the immich database role actually has — a mismatch, not a broken database.
Rather not fix this by hand? SparkBox ships a one-command repair for exactly this: sudo sparkbox repair-immich-db-auth proves the mismatch over a real TCP connection, backs up the database first, and rotates only the immich role's password without ever putting the secret in your shell history. See the walkthrough →
The 10-second version: Back up the database, stop Immich, reset the immich Postgres role's password using psql's \password command, then update Immich's connection settings to match the new password before restarting.
Why this happens
Postgres supports different authentication rules depending on how a connection is made. A very common setup trusts connections that come in over the local Unix socket on the same machine — no password required — while requiring an actual password for connections that come in over TCP (a normal network connection, even if it's just to localhost).
Tools like pg_isready, and most container health checks, tend to connect over that trusted local socket. So they report the database as healthy — because as far as Postgres and the socket are concerned, everything's fine. Immich, though, connects over TCP with an actual username and password. If that password has drifted out of sync with what's stored in Postgres — because it was changed in one place and not the other, restored from an old backup, or reset outside of Immich's own config — Immich gets rejected with 28P01 while your health check keeps insisting nothing's wrong.
That's the trap: you can restart Postgres, restart Immich, check disk space, and stare at a "healthy" database container for an hour, because the check you're trusting isn't testing the same thing Immich is actually doing.
Step 1: Confirm it's actually a password mismatch
- Check the Immich or Postgres logs for the exact error. Look for
28P01or wording like "password authentication failed for user." - If your logs mention a different Postgres error code, this guide isn't the right fix —
28P01specifically means invalid credentials, not corruption or a crashed process. - Don't trust a green "healthy" status on its own. If you can, try connecting with the exact same credentials Immich uses, over TCP rather than the local socket, to reproduce the failure directly.
Step 2: Back up the database before changing anything
Before touching credentials, take a fresh dump of the database. If something else turns out to be wrong, you want a clean snapshot from right before you started poking at it.
pg_dump -U postgres -h localhost immich > immich_backup.sql
Don't skip this. If the dump command fails for any reason, stop and investigate that first — a failed backup usually means something else is already wrong with the database connection, and changing the password on top of that will only make diagnosing it harder.
Step 3: Stop Immich before you rotate the password
Stop the Immich app (or its container) so nothing is actively trying to write to the database with the old, now-mismatched credentials while you're mid-change. Leave Postgres itself running — you need it up to reset the role's password.
Step 4: Reset the immich role's password with psql
Connect to Postgres as an admin user (commonly postgres), then use psql's built-in \password command to reset the immich role. This is the safest way to do it because the new password is typed interactively — it never appears in your shell history, in a running process list, or in a script's argument list.
psql -U postgres
\password immich
You'll be prompted to type the new password twice. Choose something you can reliably copy into a config file afterward — avoid characters that need special escaping in your config format if you can.
Step 5: Update Immich's connection settings to match
Immich needs to know about the new password too. Update whatever file or environment variable holds your database credentials (commonly a DB_PASSWORD-style setting in your Immich environment configuration) so it matches exactly what you just set in psql.
Gotcha: a mismatch here is exactly how you end up back at 28P01 five minutes later. Double-check for stray spaces, quote characters that got dropped, or an old cached copy of the config that a restart pulls from instead of the one you just edited.
Step 6: Restart and verify
- Start Immich back up.
- Watch the logs as it starts — you should see a successful database connection instead of
28P01. - Confirm the app actually loads your library, not just that the log looks clean, since a healthy connection message doesn't always mean every query is working.
Frequently asked
What does Postgres error 28P01 mean in Immich?
28P01 is Postgres's standard code for invalid_password. It means the credentials Immich sent when connecting to the database don't match what the database role actually has stored. It's not data corruption and it's not a crashed database — it's a login mismatch.
Why does my Postgres health check say everything is fine if the password is wrong?
Most container health checks and tools like pg_isready connect over a local Unix socket, which many Postgres setups trust automatically without checking a password. Immich connects over TCP with a real password, so only a TCP-based check will actually reproduce the failure the app is hitting.
Will resetting the Postgres password delete my Immich photos or library?
No. Resetting the immich role's password only changes how the app authenticates — it doesn't touch your photo files or the rows in the database. Still, always take a fresh backup with pg_dump before changing anything, in case something else is also wrong.
Can I just put the new password in the docker run command or .env file directly?
You can, but it's worth being careful: passwords passed as command-line arguments can end up in shell history or process listings. Setting the password interactively inside psql with \password, then only writing the final value into your Immich config file, keeps it out of logs and history.
Skip the manual credential surgery
SparkBox's repair-immich-db-auth command runs this exact fix for you: it proves the mismatch over a real TCP connection first, refuses to run unless the database is actually healthy and answering queries, takes a fresh backup before touching anything, stops the app, and rotates only the immich role's password through psql's own prompt — never as a plain argument.