Skip to main content

Using mysqldump to create database backups

In this lesson you will use mysqldump to create logical backups of your WordPress databases. You'll learn the handful of options that matter for consistent, reliable backups, why the root account is the right tool for the job, and write a script that dumps and compresses every site on your server.

mysqldump is a command-line utility that creates logical database backups. It's got plenty of options and can be a bit overwhelming if you haven't used it before. Luckily, there are only a handful of options you'll need to learn to use this tool properly. On MariaDB you'll also find it as mariadb-dump, which is the exact same tool under a different name.

Credentials vs root

Running mysqldump typically requires us to provide the hostname, database username and password using the -h, -u and -p options respectively, for example:

mysqldump -hlocalhost -uuncached -pverysecret dbname

Note the slightly uncommon lack of spaces between the option and the value.

While this method generally works, there are a couple of problems with this approach. First, the credentials may appear in the process list, so it's best to either provide them in a secure configuration file, or enter the password interactively by leaving the password blank.

Second, from a backups perspective, we don't really want to use specific site credentials, as these may need to be rotated, sites may be moved or recreated, and so on, creating additional work every time a site is changed.

We can create a special user for backups, with access to all databases, but it's also perfectly fine to simply use root. By default, this user in MySQL and MariaDB does not have a password, is only allowed to connect via a local socket, and requires the connecting Linux user to actually be root. This, of course, works with sudo as well:

sudo mysqldump dbname

Some tutorials recommend setting a strong root password for the MySQL user, however that actually makes it less secure, allowing non-root users to connect as root by knowing (or guessing) the password.

All databases vs single database

The mysqldump program allows us to create a logical backup of a single database, multiple databases, and even --all-databases if necessary.

I personally prefer to always use single database backups, even if it means iterating over multiple sites and running mysqldump more than once. This ensures that one file contains the data for one site, so I can be more confident when running restores.

Single-database backups also allow for more flexibility in retention rates, frequency and so on. However in this course we'll be sticking to a global configuration/script for all our hosted sites.

Single transaction

If you're running InnoDB tables (and you should be!) then --single-transaction is probably the most important option you will use. It ensures data consistency across all tables, and does so without locking all of the tables for the duration of the backup.

This is especially important with larger datasets and highly dynamic sites, such as WooCommerce and LMS, which can change data very often in a non-transactional way.

The database backup script

You can find the full up to date script in the config repository on GitHub, but I will explain some of the logic used to write that script here.

First, we generate our timestamp. Then loop through all the public_html directories available in the /sites/ directory. Note that this includes our phpMyAdmin install and likely other helper utilities in the future. We need to ensure we're looking at WordPress sites:

TIMESTAMP=$(date +%Y%m%d-%H%M%S)
for docroot in /sites/*/public_html; do
    [ -d "$docroot" ] || continue
    [ -f "$docroot/wp-config.php" ] || continue

Next, we figure out the site name, as well as the user that owns our wp-config.php file. This is important for the next step as we do not want to run WP-CLI as the root user for security reasons.

    site=$(basename "$(dirname "$docroot")")
    user=$(stat -c '%U' "$docroot/wp-config.php")

We read the DB_NAME constant using WP-CLI as the user that owns the wp-config.php file using sudo:

    db_name=$(sudo -u "$user" -H -- wp config get DB_NAME --path="$docroot" --skip-plugins --skip-themes 2>/dev/null) || {
        echo "[$site] could not read DB_NAME, skipping" >&2
        continue
    }

Finally, we create the destination directory, run the mysqldump backup and compress the output using gzip:

    dest_dir="/backups/$site"
    mkdir -p "$dest_dir"
    dest_file="$dest_dir/${TIMESTAMP}.sql.gz"

    echo "[$site] dumping $db_name to $dest_file"
    if mysqldump --single-transaction --quick "$db_name" | gzip > "$dest_file"; then
        echo "[$site] done"
    else
        echo "[$site] mysqldump failed" >&2
        rm -f "$dest_file"
    fi
done

I called this script backup-dbs.sh and placed it in the /config/bin/ directory. It needs to be run as root to write the destination backup files, as well as to access the MySQL root account. To invoke this as my karl user I'll need sudo:

This article is for premium members only. One-time payment of $196 unlocks lifetime access to all existing and future content on wpshell.com, and many other perks.