Colorado mountains

Automating MySQL Backups

This script has been heavily overhauled in the revised version (5/15/2017). Left here for history.

I recently began having a lot of trouble with my hosting company — site going down, database server not running for days on end, shell access disappearing, unanswered support emails, the works. So I switched to a new hosting company. One thing I used a lot was shell scripting and crons.

One new wrinkle was that the new host had every MySQL database on their own virtual server. I had been using phpMyBackupPro for backups, but it can't handle multiple servers. I decided to roll my own solution. Turns out, it took about an hour.

My requirements:

  • Runs with a shell script in any/most Linux distros and Mac
  • Extracts databases from multiple servers or users
  • Compresses the text to conserve disk space
  • Emails me the backups for safe-keeping
  • Runs from cron so it won't miss

The database dump using mysqldump works fine. For compression without creating intermediate files, use a named pipe:

# Create a pipe named 'pipe'
mkfifo pipe

# Set the input/output
gzip -9 < pipe > ~/db_backups/database.sql.gz &

# Run the actual dump to the pipe
mysqldump -h hostname -u username -ppassword -q \
  --add-drop-table --extended-insert database > pipe

# Get the return code of mysqldump
result=$?

# Wait until gzip completes
wait

# Remove the pipe
rm pipe

For multiple servers, repeat the gzip and mysqldump lines for each server.

To email the backups, use PHPMailer. Save as send_backups.php:

<?php
$to_address   = 'your_name@gmail.com';
$from_address = 'backups@your_domain.com';
$subject      = 'MySQL Backup';
$body         = 'Database backup files attached.';

require_once('class.phpmailer.php');

date_default_timezone_set('America/Denver');
define('DS', DIRECTORY_SEPARATOR);
$path = dirname(__FILE__);

$mail = new PHPMailer();
$mail->From     = $from_address;
$mail->FromName = 'Backup Agent';
$mail->Subject  = $subject . ' - ' . date('Y-m-d H:i:s');
$mail->Body     = $body;
$mail->AddAddress($to_address, 'Backup Recipient');

foreach (glob('*.gz') as $filename) {
    $mail->AddAttachment($path . DS . $filename);
}

$mail->Send();

The crontab entry — backup every two hours, email once a day:

50 */2 * * * ~/db_backups/database_backup.sh
00 23 * * * /usr/local/bin/php5 ~/db_backups/send_backups.php

Update 8/5/2013: This script ran flawlessly, unattended, since installation in 2008.