How to dump and restore a Postgres DB with new table ownership
I've used MySQL for years. But recently, I found myself working with PostgreSQL and simple things like dumping and restoring a database are different enough that I decided to document the process. It's straightforward enough once I knew how.
So first, I'll do a quick overview and then share the explanations afterwards.
Quick Overview
There are several ways to dump and restore data in Postgres if you have more specialist needs. I've chosen one almost analogous to how I would do it with MySQL.
Requirements
You need the correct privileges to both dump the database and recreate all the database objects.
Set the user credentials
Instead of passing options to pg_dump
and psql
, we can also set up our access credentials as environment variables. There are more secure alternatives to handling database access secrets though.
export PGHOST=<host>
export PGUSER=<user>
export PGPASSWORD=<password>
Dumping the data
Notice how we dump the data with the --no-privileges
and --no-owner
. Don't include this if you want to keep the ownership as is.
pg_dump \
--no-privileges \
--no-owner \
dbname > dbname.sql
Creating the new database
Create a new database from a template.
psql \
-c "CREATE DATABASE newdb TEMPLATE template0;"
Restoring the data
Notice I used --single-transaction
to import the data. If you don't mind importing the data where there are some errors, remove that option.
psql \
--single-transaction \
new_db < dbname.sql
Changing table ownership
Finally, when working with MySQL, I don't have to worry about table ownership. I just use grants and privileges. But when you import data in Postgres, it assumes the owner is the user associated with the connection. One way I've seen how to change table ownership to one we want is to generate the ALTER
commands and then run that.
psql newdb
Then within the psql
shell, we create the ALTER
commands.
## :psql >>
select 'ALTER TABLE ' || t.tablename || ' OWNER TO new_owner;'
from pg_tables t
where t.tableowner != 'rdsadmin';
It will print out something like the following, which you will need to copy-paste, and run within the shell again.
## :psql >>
ALTER TABLE groups OWNER TO new_owner;
ALTER TABLE images OWNER TO new_owner;
ALTER TABLE jobs OWNER TO new_owner;
And that's it.
We've dumped the database.
We've restored it.
And we've changed the table ownership to what we want.
Now, I'll share a few things I found in the documentation.
Notes on how the dump and restore work
Libpq
Libpq is the "C application programmer's interface to PostgreSQL". So I needed to install Libpq before being able to run some commands on my local environment. For me on MacOS, it was not installed with Postgres and had to be done separately.
Table locks
With MySQL, dumping the database with table locks means users may experience slow responses or even downtime. To prevent table locks in MySQL, we can do the following:
mysqldump \
--single-transaction \
--skip-lock-tables \
dbname > dbname.sql
The --single-transaction
tells the mysqldump
to "put everything into a transaction", and "read the database in the current state and create a consistent data dump". But it will still lock the tables unless we provide --skip-lock-tables
. That way, we get a consistent data output and no table locks.
↗️ Run mysqldump without locking the tables - https://mysqldump.guru/run-mysqldump-without-locking-the-tables.html
In Postgres, this is not a problem as "dumps created by pg_dump are internally consistent, that is, updates to the database while pg_dump is running will not be in the dump. pg_dump does not block other operations on the database while it is working." Therefore, no extra options are needed. Of course, there are exceptions.
↗️ Chapter 9. Backup and Restore - https://www.postgresql.org/docs/7.2/backup.htm
Using options instead of environment variables for connection settings
Similar to MySQL, we have -h host
, -p port
, but we have -W password
for the prompt and a capital U
for -U user
.
Removing ownership
If you want the table ownership and privileges to remain the same, providing --no-privileges
and --no-owner
is not necessary. However, without this, you get the following SQL in your SQL dump:
CREATE SCHEMA abc;
ALTER SCHEMA abc OWNER TO existing_user;
Database Templates
Database Templates in Postgres is a foreign concept to me in MySQL. However, when we do, CREATE DATABASE
in Postgres, it's an alias for CREATE DATABASE dbname TEMPLATE template1
.
Now, there are two templates by default. template0
and template1
. In the earlier example, I used template0
, but why?
template1
can be amended so you can create a new database with your customisations.template0
doesn't have any customisations. So it's a pure, unadulterated database that you can clone and copy.
All-or-nothing imports
Something interesting we can do in Postgres is ensure our imported data is consistent. If there are any errors when importing the dumped file, it will roll back all changes. To do this, we use --single-transaction
on the import:
psql \
--single-transaction \
< dumpfile.sql
Note: "When using this mode, be aware that even a minor error can rollback a restore that has already run for many hours. However, that might still be preferable to manually cleaning up a complex database after a partially restored dump." - postgresql.org
That wasn't so bad
MySQL and Postgres are similar but they're not the same. Hopefully dumping and restoring in Postgres will be simpler (even if it's just for me) in future.
Subscribe to my newsletter
Read articles from Gemma Black directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Gemma Black
Gemma Black
I'm a Senior Software Engineer. With 10+ years working within tech teams, and 20+ years working with code, I develop across the stack, assisting with application design, maintenance, deployment and DevOps within the AWS Cloud.