Set Up Automated MySQL Backups on Ubuntu VPS: Complete Guide

By Raman Kumar

Share:

Updated on May 01, 2026

Set Up Automated MySQL Backups on Ubuntu VPS: Complete Guide

Prerequisites and Initial Setup

Before setting up automated MySQL backups on Ubuntu VPS, you'll need root or sudo access and MySQL installed. Basic command line knowledge helps too.

Check your MySQL installation and see which databases need backing up:

sudo mysql -u root -p
SHOW DATABASES;
EXIT;

Create a dedicated backup directory with proper permissions:

sudo mkdir -p /var/backups/mysql
sudo chown mysql:mysql /var/backups/mysql
sudo chmod 750 /var/backups/mysql

This keeps your backups organized and secure. The mysql user ownership prevents permission errors when backup scripts run.

Create MySQL Backup User with Limited Privileges

Never use root credentials in backup scripts. Create a dedicated backup user instead to limit security risks.

Connect to MySQL and create the backup user:

sudo mysql -u root -p

CREATE USER 'backup_user'@'localhost' IDENTIFIED BY 'strong_backup_password';
GRANT SELECT, SHOW VIEW, TRIGGER, LOCK TABLES, RELOAD ON *.* TO 'backup_user'@'localhost';
FLUSH PRIVILEGES;
EXIT;

Store these credentials securely in a MySQL configuration file:

sudo nano /root/.my.cnf.backup

Add this content:

[mysqldump]
user=backup_user
password=strong_backup_password
single-transaction=true
routines=true
triggers=true

Lock down the file permissions:

sudo chmod 600 /root/.my.cnf.backup
sudo chown root:root /root/.my.cnf.backup

Build the Backup Script

Create a complete backup script that handles database dumps, compression, and cleanup.

sudo nano /usr/local/bin/mysql-backup.sh

Add this backup script:

#!/bin/bash

# MySQL Backup Script for Ubuntu VPS
# Configuration
BACKUP_DIR="/var/backups/mysql"
MYSQL_CONFIG="/root/.my.cnf.backup"
DATE=$(date +"%Y%m%d_%H%M%S")
RETENTION_DAYS=30
LOG_FILE="/var/log/mysql-backup.log"

# Function to log messages
log_message() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$LOG_FILE"
}

# Function to backup individual database
backup_database() {
    local db_name=$1
    local backup_file="$BACKUP_DIR/${db_name}_${DATE}.sql.gz"
    
    log_message "Starting backup for database: $db_name"
    
    # Create compressed dump
    if mysqldump --defaults-file="$MYSQL_CONFIG" \
        --single-transaction \
        --routines \
        --triggers \
        --add-drop-database \
        --create-options \
        "$db_name" | gzip > "$backup_file"; then
        
        log_message "Successfully backed up $db_name to $backup_file"
        echo "Backup completed: $backup_file ($(du -h "$backup_file" | cut -f1))"
    else
        log_message "ERROR: Failed to backup database $db_name"
        echo "ERROR: Backup failed for $db_name"
        return 1
    fi
}

# Function to clean old backups
cleanup_old_backups() {
    log_message "Starting cleanup of backups older than $RETENTION_DAYS days"
    
    find "$BACKUP_DIR" -name "*.sql.gz" -type f -mtime +$RETENTION_DAYS -delete
    
    local deleted_count=$(find "$BACKUP_DIR" -name "*.sql.gz" -type f -mtime +$RETENTION_DAYS | wc -l)
    log_message "Cleanup completed. Removed $deleted_count old backup files"
}

# Main execution
log_message "Starting MySQL backup process"

# Get list of databases (excluding system databases)
databases=$(mysql --defaults-file="$MYSQL_CONFIG" -e "SHOW DATABASES;" | grep -Ev "^(Database|information_schema|performance_schema|mysql|sys)$")

if [ -z "$databases" ]; then
    log_message "WARNING: No user databases found to backup"
    echo "No user databases found to backup"
    exit 1
fi

# Backup each database
for db in $databases; do
    backup_database "$db"
done

# Clean up old backups
cleanup_old_backups

log_message "MySQL backup process completed"
echo "All database backups completed successfully"

Make the script executable:

sudo chmod +x /usr/local/bin/mysql-backup.sh

Test Your Backup Script

Test the script manually before automating it.

sudo /usr/local/bin/mysql-backup.sh

Check that backup files were created:

ls -la /var/backups/mysql/

Review the log file for any errors:

tail -n 20 /var/log/mysql-backup.log

Test backup integrity by restoring a small database:

# Create test database
mysql -u root -p -e "CREATE DATABASE test_restore;"

# Find a recent backup file
zcat /var/backups/mysql/your_database_20261201_120000.sql.gz | mysql -u root -p test_restore

# Verify restoration worked
mysql -u root -p -e "SHOW TABLES;" test_restore

Schedule Automated MySQL Backups with Cron

Configure cron to run your backup script automatically. Choose a schedule that balances backup frequency with server load.

Open the root crontab:

sudo crontab -e

Add one of these scheduling options:

# Daily backup at 2:30 AM
30 2 * * * /usr/local/bin/mysql-backup.sh > /dev/null 2>&1

# Twice daily (2:30 AM and 2:30 PM)
30 2,14 * * * /usr/local/bin/mysql-backup.sh > /dev/null 2>&1

# Weekly backup on Sunday at 3:00 AM
0 3 * * 0 /usr/local/bin/mysql-backup.sh > /dev/null 2>&1

Your schedule depends on how often your data changes and your recovery needs. Daily backups protect most applications without using excessive storage.

Verify your cron job is scheduled:

sudo crontab -l

Monitor and Maintain Your Backup System

Regular monitoring keeps your automated MySQL backups running reliably. Set up these monitoring practices:

Create a simple monitoring script:

sudo nano /usr/local/bin/backup-status.sh
#!/bin/bash

BACKUP_DIR="/var/backups/mysql"
LOG_FILE="/var/log/mysql-backup.log"

echo "=== MySQL Backup Status ==="
echo "Last backup files:"
ls -lt "$BACKUP_DIR"/*.sql.gz | head -5

echo -e "\n=== Recent log entries ==="
tail -n 10 "$LOG_FILE"

echo -e "\n=== Storage usage ==="
du -sh "$BACKUP_DIR"

echo -e "\n=== Files older than 7 days ==="
find "$BACKUP_DIR" -name "*.sql.gz" -mtime +7 -ls | wc -l
echo " backup files are older than 7 days"
sudo chmod +x /usr/local/bin/backup-status.sh

Run this periodically to check backup health:

sudo /usr/local/bin/backup-status.sh

Configure Remote Storage Options

Storing backups only on the same server creates a single point of failure. Add remote storage for better protection.

For Amazon S3 storage, install AWS CLI:

sudo apt update
sudo apt install awscli -y

Configure AWS credentials:

aws configure

Modify your backup script to include S3 upload. Add this function before the main execution:

# Function to upload to S3
upload_to_s3() {
    local backup_file=$1
    local s3_bucket="your-backup-bucket"
    local s3_path="mysql-backups/$(basename "$backup_file")"
    
    if aws s3 cp "$backup_file" "s3://$s3_bucket/$s3_path"; then
        log_message "Successfully uploaded $backup_file to S3"
    else
        log_message "ERROR: Failed to upload $backup_file to S3"
    fi
}

For VPS hosting customers who prefer simpler solutions, use rsync to copy backups to another server:

# Add to backup script after database backup
rsync -avz "$BACKUP_DIR/" user@backup-server:/remote/backup/path/

Troubleshooting Common Issues

Here's how to fix common backup problems:

Permission Errors: If backups fail with permission denied, check directory ownership and MySQL user privileges:

sudo chown -R mysql:mysql /var/backups/mysql
sudo chmod -R 750 /var/backups/mysql

Large Database Timeouts: For databases over 1GB, add timeout settings to your MySQL configuration:

# Add to /root/.my.cnf.backup
max_allowed_packet=1024M
lock_wait_timeout=300

Storage Space Issues: Monitor backup directory size and adjust retention policy:

df -h /var/backups/
du -sh /var/backups/mysql/

Cron Job Not Running: Check cron service status and logs:

sudo systemctl status cron
sudo journalctl -u cron -f

This backup setup works well with our database replication tutorials for comprehensive data protection.

Security Best Practices

Protect your backup system with these security measures:

Encrypt backup files at rest by modifying the backup function:

# Replace the mysqldump line with:
mysqldump --defaults-file="$MYSQL_CONFIG" \
    --single-transaction \
    --routines \
    --triggers \
    "$db_name" | gzip | openssl enc -aes-256-cbc -salt -k "$ENCRYPTION_KEY" > "$backup_file.enc"

Secure credential files with appropriate permissions:

sudo chmod 600 /root/.my.cnf.backup
sudo chattr +i /root/.my.cnf.backup  # Make file immutable

Consider using dedicated backup networks or VPNs for remote transfers. This is especially important for customers using our managed VPS services who handle sensitive data.

Setting up reliable automated MySQL backups requires careful planning and ongoing maintenance. Our managed VPS hosting includes automated backup solutions and 24/7 technical support to help you implement robust database protection strategies.

Frequently Asked Questions

How often should I run automated MySQL backups?

Daily backups work well for most applications. High-change databases may need twice-daily backups, while less critical databases can use weekly schedules. Consider your recovery point objective (RPO) when deciding frequency.

What's the difference between mysqldump and MySQL binary logs?

Mysqldump creates logical backups (SQL statements) that are portable and human-readable. Binary logs provide point-in-time recovery capability. Use mysqldump for scheduled backups and enable binary logging for complete protection.

How much storage space do compressed MySQL backups require?

Compression typically reduces backup size by 60-80%. A 1GB database usually compresses to 200-400MB. Monitor your backup directory size and adjust retention policies based on available disk space.

Can I backup MySQL while the database is in use?

Yes, the --single-transaction flag creates consistent backups from active databases. This works for InnoDB tables but may lock MyISAM tables briefly. Schedule backups during low-traffic periods when possible.

How do I test backup integrity without affecting production?

Create a separate test database and restore backups there regularly. Set up a staging environment that mirrors production for comprehensive backup testing. This process should be part of your regular maintenance routine.