Restoring Our Companygids Database After a Credential Mix-Up

Yesterday’s environment migration from the old user account to a fresh setup went smoothly until it didn’t: Django ran, but the admin login exploded with relation "auth_user" does not exist. That error was the canary in the coal mine—our Postgres volume had been re‑initialised without any of the existing tables. In other words, my production data was gone and Django’s migrations hadn’t been reapplied.

What Went Wrong

The culprit turned out to be a mismatch in database credentials during the handover. I spun up the new container with different POSTGRES_USER/ POSTGRES_PASSWORD values than the ones that originally populated the volume. Because the container name was reused, Postgres didn’t reprovision the user—so from Django’s point of view the password was wrong, migrations failed silently, and the database ended up empty.

Recovery Plan

  1. Stop and remove the broken container:
    docker stop companygids-postgres
      docker rm companygids-postgres
  2. Recreate the service with the original credentials:
    docker compose up -d db

    The key is that POSTGRES_USER and POSTGRES_PASSWORD must match whatever was used when the database dump was taken.

  3. Restore the backup:
    PGPASSWORD='pwd4companygids' pg_restore \
        --clean --if-exists --no-owner --no-privileges -j 4 \
        -h 127.0.0.1 -U companygids_user -d companygids \
        /home/sergej/Documenten/companygids_nl/companygids-20251008-1049.dump

    This brings back every table, index, and constraint from the dump. The --clean flag ensures that any half-baked schema created during the failed run is wiped first.

  4. Run Django migrations:
    source .venv/bin/activate
      python manage.py migrate
  5. Recreate the superuser if necessary:
    python manage.py createsuperuser

Lessons Learned

  • Always keep track of the original Postgres username and password. Changing either while reusing a named volume leaves the old credentials in place and locks your app out.
  • Never assume an empty schema means success—check for existing tables with \dt before celebrating.
  • Keep fresh dumps (and the commands used to create and restore them) documented. Having yesterday’s backup and the exact pg_restore command saved hours today.

After restoring with the correct credentials, the admin login and the entire Django stack came back to life. Painful lesson, but the data is safe again.

Comments