149

I did backup on database on different server and that has different role than I need, with this command:

pg_dump -Fc db_name -f db_name.dump

Then I copied backup to another server where I need to restore the database, but there is no such owner that was used for that database. Let say database has owner owner1, but on different server I only have owner2 and I need to restore that database and change owner.

What I did on another server when restoring:

createdb -p 5433 -T template0 db_name 
pg_restore -p 5433 --role=owner2 -d db_name db_name.dump

But when restore is run I get these errors:

pg_restore: [archiver (db)] could not execute query: ERROR:  role "owner1" does not exist

How can I specify it so it would change owner? Or is it impossible?

Andrius
  • 19,658
  • 37
  • 143
  • 243
  • 2
    Besides `--no-owner` as suggested in the accepted answer, you may also need `--no-privileges`. See [this answer](https://stackoverflow.com/a/57748887/111036) – mivk Sep 01 '19 at 19:32

3 Answers3

209

You should use the --no-owner option, this stops pg_restore trying to set the ownership of the objects to the original owner. Instead the objects will be owned by the user specified by --role

createdb -p 5433 -T template0 db_name 
pg_restore -p 5433 --no-owner --role=owner2 -d db_name db_name.dump

pg_restore doc

  • 26
    `pg_dump --no-owner` should also do it – Nick Barnes Jul 17 '15 at 07:39
  • 19
    My preference is to defer these sort of decisions until the restore. If you do it at the dump stage it means you can't change your mind without doing export. Doing it at the restore means that options are left open in case you decide that you really should have created that missing role etc. – Gary - Stand with Ukraine Jul 17 '15 at 07:45
  • 1
    So if I want to change owner, I must backup without owner? Cause I thought I could change owner when restoring. But even setting `--role` on different owner, it still was trying to use original owner (but then i didn't use `--no-owner`. – Andrius Jul 17 '15 at 07:48
  • @Gary: Fair enough, but attaching it to `pg_dump` is probably your only option for an SQL-format backup. I know that's not the case here, but I thought it might be useful for someone in the future... – Nick Barnes Jul 17 '15 at 07:48
  • 3
    @Andrius: You don't need to change your backup, Gary's answer should solve your problem – Nick Barnes Jul 17 '15 at 07:53
  • 10
    Looking through all the posts on this topic, they also seem to skip over the fact that this approach requires the new role owner to be a superuser, at least for the during of the restore. Then everything works – chrismarx Jan 22 '18 at 21:08
  • 1
    Is there a way to do same thing but with `psql`? Question is [here](https://stackoverflow.com/q/63336536/4632019) – Eugen Konkov Aug 10 '20 at 08:25
  • 1
    It's possible to use --no-owner and --no-privileges on both dump and restore, and when I don't want to backup and restore the owner, I prefer to use it on both dump and restore – Benjamin Atkin Oct 11 '20 at 19:58
  • The --no-privileges part was what I was missing. Thanks! – jpierson May 21 '21 at 12:25
  • 2
    @chrismarx It's possible to use `-U ` and `--role ` instead. – not2savvy Jan 18 '23 at 10:11
11

The above answer was helpful but ultimately didn't get me 100% there for my case so I thought I would share an iteration on the above for people with similar cases to myself.

In my scenario I may have staging and production databases with different names and different owners. I may need to migrate the staging database to replace the production database but with different name and different owner.

Or perhaps I need to restore a daily backup but change the name or owner for some reason.

Our permissions are fairly simple as each app gets own db/user so this won't help people with complicated user/role/permissions setups.

I tried using the create from template approach to copy the db but this fails if any users/connections are active on the source db so this doesn't work with live source dbs.

With a basic --no-owner restore, the db/table owners on the restored/new db are the user executing the commands (e.g. postgres)...so you will have an additional step to fix all the db permissions. As we have a single app-specific-user per-db setup, we can make things easier.

I want my app-specific-user to own the db/tables even if they don't have permission to create the db in the first place.

The basic idea is:

  • dump the source db with --no-owner and --no-privileges
    • --clean shouldn't be needed as we will restore into a new/empty DB.
  • drop the target db if it already exists.
  • re-create the target DB (empty) setting the owner to our target user (already exists, if not need to create).
  • restore the dump to the empty target AS THE TARGET USER
    • --no-owner --no-privileges ensures the target user owns everything and no ownership/privs get carried over from the dump we made.
    • --no-privileges and --no-owner are redundant here as we already excluded them when we dumped. So there are some redundant flags in the below example which you may not need if you are confident about how your dump was made.

Note that I am ditching any privs/ownership as I have a single user per db as db owner with full rights. If you have a more complicated permissions structure this may not be appropriate. Or perhaps you do the restore with single user and then let your server provisioning system add any missing roles/privs to the restored DB.

Example

Setup some vars...

DB_NAME_SRC="app_staging"
DB_NAME_TARGET="app_production"
DB_TARGET_OWNER="app_production_user"
DUMP_FILE="/tmp/$DB_NAME_SRC"

Then do backup/restore

# backup clean/no-owner
sudo -i -u postgres pg_dump --format custom --clean --no-owner --no-privileges "$DB_NAME_SRC" > "$DUMP_FILE"

# THE FOLLOWING HAPPENS ON THE PG box where you want to restore

# drop target if exists - doesn't work for db with active users/connections
sudo -i -u postgres dropdb   -U postgres --if-exists  "$DB_NAME_TARGET"

# recreate target db, specifying owner to be the target user/role
# DB_TARGET_OWNER must already exist in postgres or you need to create it
sudo -i -u postgres createdb -U postgres --owner "$DB_TARGET_OWNER" -T template0 "$DB_NAME_TARGET"

# do the restore to the target db as the target user so any created objects will be owned by our target user.
sudo -i -u postgres pg_restore --host localhost --port 5432 --username "$DB_TARGET_OWNER" --password --dbname "$DB_NAME_TARGET" --no-owner --no-privileges "$DUMP_FILE"

# now in this simple case I don't need an additional step of fixing all the owners/permissions because the db and everything in it will be owned by the target user.

Note that in the restore section I connected over the network with password instead of locally so I didn't have to change postgres local user authentication from peer to password. My db app-specific users are not local users anyway.

mattpr
  • 2,504
  • 19
  • 17
  • _"With a basic --no-owner restore, the db/table owners on the restored/new db are the user executing the commands (e.g. postgres)...so you will have an additional step to fix all the db permissions"._ That's why the accepted answer tells you to use `--no-owner` with `--role `! – not2savvy Jan 18 '23 at 10:14
  • Thanks. Not sure why I missed the `--role` flag in the previous example. The `--role` documentation focuses on using the flag when not having enough perms to perform the restore...nice to know it also impacts the resulting table ownership (although logical). I do find it useful to also add the `--owner` when doing `createdb` if you want the resulting database to also be owned by the new user. To be honest, re-reading my answer ("I tried using the create from template approach") I may have added my answer in the "wrong tab" when testing this. I appreciate your comment. – mattpr Jan 18 '23 at 13:11
  • The following command will kill any active connections on the target host: `sudo -i -u postgres psql -h "$DB_TARGET_HOST" -U postgres -c "SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity WHERE pg_stat_activity.datname = '$DB_NAME_TARGET' AND pid <> pg_backend_pid();"` But you need define DB_TARGET_HOST first. – Dom Jan 27 '23 at 20:46
1

If you are looking for heroku. first create a sql dump file with no owner. And then load it to heroku.

pg_dump -O target_db -f mydb.sql
heroku pg:psql < mydb.sql

-O is used here for no-owner.

Using .sql file to restore is good idea instead of .dump file. (.dump file is need to uploaded on a downloaded url)

Rahul Rajput
  • 298
  • 4
  • 11
  • If you are using rails, then I think this [answer might help](https://stackoverflow.com/questions/8342642/how-can-i-import-a-sql-file-into-a-rails-database/28874165). – Rahul Rajput May 16 '23 at 15:07