How to Rename a PostgreSQL Database During Export/Import: Solving Role and DB Name Conflicts


2 views

When working with PostgreSQL database migrations between environments (production → development/staging), developers frequently encounter ownership and naming conflicts. Unlike MySQL where database names aren't hardcoded in dumps, PostgreSQL includes specific references that cause these errors:

ERROR:  role "blah" does not exist
WARNING:  database "blah" does not exist

PostgreSQL's dump files contain three problematic elements:

  • Database name references in COMMENT statements
  • Role/owner specifications in ALTER TABLE commands
  • Schema-level permissions (ACL entries)

The cleanest approach is using these pg_dump options:

pg_dump --no-owner --no-acl --format=custom -f blah.dump blah_production

Then restore with:

pg_restore --no-owner --no-acl -d blah_development blah.dump

Key flags explanation:
--no-owner: Skips OWNER TO statements
--no-acl: Omits privilege assignments
--format=custom: Enables selective restore

For plain SQL dumps, you can combine sed with pg_dump:

pg_dump blah_production | \
sed -e 's/blah_production/blah_development/g' \
    -e 's/OWNER TO blah/OWNER TO current_user/g' \
    -e 's/COMMENT ON DATABASE blah/-- COMMENT ON DATABASE blah/g' \
    > modified_dump.sql

When you need to preserve certain ownership structures, create the roles first:

-- Before restore
CREATE ROLE blah_devel WITH LOGIN;
ALTER DATABASE blah_development OWNER TO blah_devel;

-- Then restore with:
pg_restore --role=blah_devel -d blah_development blah.dump

For automated environments, use this bash script template:

#!/bin/bash

SRC_DB="blah_production"
TARGET_DB="blah_${ENVIRONMENT}"
DUMP_FILE="/tmp/db_dump.pgcustom"

pg_dump --no-owner --no-acl --format=custom -Fc -f $DUMP_FILE $SRC_DB

psql -c "CREATE DATABASE $TARGET_DB;"
pg_restore --no-owner --no-acl -d $TARGET_DB $DUMP_FILE

# Verify restoration
psql -d $TARGET_DB -c "SELECT count(*) FROM pg_tables WHERE schemaname = 'public';"

If you encounter:

ERROR:  must be owner of database

Solution:

psql -c "ALTER DATABASE blah_development OWNER TO current_user;"

When working with PostgreSQL database migrations between environments (production → development/staging), we often encounter permission and naming conflicts. Unlike MySQL where database names aren't hardcoded in dumps, PostgreSQL includes explicit references to:

COMMENT ON DATABASE original_name;
ALTER TABLE public.table_name OWNER TO original_role;

Here are three production-tested approaches:

1. Using pg_dump with --no-owner

The most straightforward solution:

pg_dump --no-owner --format=c original_db > dump.file
pg_restore -d new_db_name dump.file

This prevents ownership assignments during restore. You'll need to manually set permissions afterward with:

GRANT ALL ON SCHEMA public TO new_role;
GRANT ALL ON ALL TABLES IN SCHEMA public TO new_role;

2. Creating a Template Database

For repeated migrations:

CREATE DATABASE template_db TEMPLATE original_db;
UPDATE pg_database SET datistemplate = FALSE WHERE datname = 'template_db';
CREATE DATABASE new_db_name TEMPLATE template_db;

3. Using Custom Format with pg_restore Options

For maximum control:

pg_dump -Fc original_db > dump.file
pg_restore \
  --dbname=new_db_name \
  --no-owner \
  --no-privileges \
  --role=target_role \
  dump.file

When you need to preserve specific permissions but change others:

# Dump with comments but without owners
pg_dump -Fc --no-owner --no-acl original_db > dump.file

# Restore with custom permissions
pg_restore -d new_db_name \
  --use-list=permissions.lst \
  dump.file

Create permissions.lst containing:

COMMENT ON DATABASE
GRANT ALL ON SCHEMA public TO
GRANT SELECT ON ALL TABLES IN SCHEMA public TO

For Rails environments, create a shell script:

#!/bin/bash

# Export
pg_dump -Fc --no-owner --no-acl ${PRODUCTION_DB} > /tmp/dump.pg

# Import
createdb ${TARGET_DB}
psql -d ${TARGET_DB} -c "CREATE ROLE ${TARGET_USER} LOGIN"
pg_restore -d ${TARGET_DB} --no-owner --no-acl /tmp/dump.pg
psql -d ${TARGET_DB} -c "GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO ${TARGET_USER}"