The PostgreSQL image has the concept of "initialization scripts" that you can put in the directory /docker-entrypoint-initdb.d.
If you would like to do additional initialization in an image derived from this one, add one or more *.sql, *.sql.gz, or *.sh scripts under /docker-entrypoint-initdb.d (creating the directory if necessary). After the entrypoint calls initdb to create the default postgres user and database, it will run any *.sql files, run any executable *.sh scripts, and source any non-executable *.sh scripts found in that directory to do further initialization before starting the service.
reference
You can use that to create a new database and then grant access to it.
Example of compose.yml:
services:
postgresql:
image: postgres:17.4
ports:
- "5432:5432"
volumes:
- "database:/var/lib/postgresql/data"
- "./docker/postgresql/initdb.d:/docker-entrypoint-initdb.d"
environment:
POSTGRES_DB: somedb
POSTGRES_USER: someuser
POSTGRES_PASSWORD: somepassword
volumes:
database:
The script ./docker/postgresql/initdb.d/init-test-db.sh can be as following:
#!/usr/bin/env bash
set -e
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
CREATE DATABASE "${POSTGRES_DB}_test";
GRANT ALL PRIVILEGES ON DATABASE "${POSTGRES_DB}_test" TO "$POSTGRES_USER";
EOSQL
Then, when the main database is created, the postgresql container will run the script and create the database somedb_test.