Paperless-ngx “PostgreSQL 14 or later is required” Error

After updating Paperless-ngx via Docker compose, I suddenly found that the service refused to start.
In your paperless-ngx compose logs you will find something like this:

webserver-1  | Connected to Redis broker.
webserver-1  | [init-redis-wait] Redis ready
webserver-1  | Connected to PostgreSQL
webserver-1  | [init-db-wait] Database is ready
webserver-1  | [init-migrations] Apply database migrations...
webserver-1  | Traceback (most recent call last):
webserver-1  |   File "/usr/src/paperless/src/manage.py", line 10, in <module>
webserver-1  |     execute_from_command_line(sys.argv)
webserver-1  |   File "/usr/local/lib/python3.12/site-packages/django/core/management/init.py", line 442, in execute_from_command_line
webserver-1  |     utility.execute()
webserver-1  |   File "/usr/local/lib/python3.12/site-packages/django/core/management/init.py", line 436, in execute
webserver-1  |     self.fetch_command(subcommand).run_from_argv(self.argv)
webserver-1  |   File "/usr/local/lib/python3.12/site-packages/django/core/management/base.py", line 416, in run_from_argv
[...]
webserver-1  |   File "/usr/local/lib/python3.12/site-packages/django/db/backends/base/base.py", line 201, in check_database_version_supported
webserver-1  |     raise NotSupportedError(
webserver-1  | django.db.utils.NotSupportedError: PostgreSQL 14 or later is required (found 13.22).
webserver-1  | s6-rc: warning: unable to start service init-migrations: command exited 1
webserver-1  | /run/s6/basedir/scripts/rc.init: warning: s6-rc failed to properly bring all the services up! Check your logs (in /run/uncaught-logs/current if you have in-container logging) for more information.
webserver-1  | /run/s6/basedir/scripts/rc.init: fatal: stopping the container.

The Important message from all this error log comes close to the end before the container is stopped again, it says:

django.db.utils.NotSupportedError: PostgreSQL 14 or later is required (found 13.22).

This means the container is running on Postgres 13 which is no longer supported.
A simple chnage of the Docker compose file from image: postgres:13 to image: postgres:17 will not be enough due postgress can not automatically convert old database to new.

Upgrading paperless to a more recent postgress

As said we need to upgrade the existing database to Postgres 14+ (in this guide: 17), while keeping your data. It absolutely makes sense to specify a fixed version number for postgress and not going image: postgres:latest, why? Simple postgress major version jumps are normally incompatible to previous versions, so on an upgrade from e.g. 16.x to 17.x you would lose access to your database because postgress container refuse to start due version missmatch.

To fix that we export our existing paperless database, setup a new recent postgress DB and user to then finally import our saved data again.


Step 1: Stop your stack

docker compose down

Step 2: Dump your existing paperless database

Bring up only the old database container and dump everything:

docker compose up db -d
docker compose exec db pg_dumpall -U paperless > dump.sql
# Stop postgress again:
docker compose down

Step 3: Update your docker-compose.yml

Change your DB service to Postgres 17 and point it to a new data directory
A new data directory is important because else docker would try to launch your postgress 17 with the data files of your old postgress, in my case 14.x.
As explained before this would cause the container to fail because postgress can’t automagically handle the old data format.
By changing the compose file volume definition from e.g. - /opt/stacks/paperless/db:/var/lib/postgresql/data to - /opt/stacks/paperless/db17:/var/lib/postgresql/data
we tell docker compose to create a new data directory for postgress 17 in db17.

db:
  image: postgres:17
  restart: unless-stopped
  volumes:
    - /opt/stacks/paperless/db17:/var/lib/postgresql/data
  environment:
    POSTGRES_DB: paperless
    POSTGRES_USER: paperless
    POSTGRES_PASSWORD: paperless

Step 4: Start the new DB and check the user

Start only the DB and check that the paperless user exists:

docker compose up db -d
docker compose exec db psql -U paperless -d paperless -c '\du'

You should see something like this:

 List of roles
 Role name |                         Attributes
-----------+------------------------------------------------------------
 paperless | Superuser, Create role, Create DB, Replication, Bypass RLS

Now we do a password reset to ensure postgress is saving the user with the required scram-sha-256 encryption.
If not you would see an error like this:

db-1         | 2025-08-29 07:45:44.175 UTC [34] FATAL:  password authentication failed for user "paperless"
db-1         | 2025-08-29 07:45:44.175 UTC [34] DETAIL:  User "paperless" does not have a valid SCRAM secret.
db-1         |  Connection matched file "/var/lib/postgresql/data/pg_hba.conf" line 128: "host all all all scram-sha-256"

To set the password again ensure to use the same credentials as specified in your compose file:

docker compose exec db psql -U paperless -d postgres -c "ALTER ROLE paperless WITH PASSWORD 'paperless';" 

Step 5: Restore your database dump

docker compose exec -T db psql -U paperless -d paperless < dump.sql

Step 6: Restart the full stack

docker compose down
docker compose up -d

Paperless should now connect to the upgraded Postgres and continue where it left off. If you double checked that everything is running as expected you can clean up the old leftover database directory “/opt/stacks/paperless/db”
Ensure not to delete to fast, first move it somewhere else or make a backup of the whole paperless.