Tools: How to Set Up Automated Database Backups on Linux (PostgreSQL and MySQL) (2026)

Tools: How to Set Up Automated Database Backups on Linux (PostgreSQL and MySQL) (2026)

How to Set Up Automated Database Backups on Linux (PostgreSQL and MySQL)

PostgreSQL Automated Backup

The Backup Script

Set Up pg_hba.conf for Passwordless Local Backup

Schedule with Cron

MySQL Automated Backup

Off-Site Backup (Critical)

Sync to S3

Test Your Backups Monthly If your production database isn't being backed up automatically, you're one bad deploy away from losing everything. This is how to set up automated backups that actually work. Add (for local connections): Or use a .pgpass file: Create a dedicated backup user: Local backups protect against mistakes. Off-site protects against server failure. A backup you've never tested is not a backup. I built ARIA to solve exactly this.

Try it free at step2dev.com — no credit card needed. Templates let you quickly answer FAQs or store snippets for re-use. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse

Command

Copy

$ -weight: 600;">sudo nano /usr/local/bin/pg-backup.sh -weight: 600;">sudo nano /usr/local/bin/pg-backup.sh -weight: 600;">sudo nano /usr/local/bin/pg-backup.sh #!/bin/bash set -e BACKUP_DIR="/var/backups/postgresql" DATE=$(date +%Y%m%d_%H%M%S) KEEP_DAYS=7 DB_NAME="${1:-all}" # Pass db name or backs up all mkdir -p "$BACKUP_DIR" if [ "$DB_NAME" = "all" ]; then # Backup all databases pg_dumpall -U postgres | gzip > "$BACKUP_DIR/all_${DATE}.sql.gz" else # Backup specific database pg_dump -U postgres -Fc "$DB_NAME" > "$BACKUP_DIR/${DB_NAME}_${DATE}.dump" fi # Remove backups older than KEEP_DAYS find "$BACKUP_DIR" -type f -mtime +$KEEP_DAYS -delete # Verify backup file exists and is not empty LATEST=$(ls -t "$BACKUP_DIR" | head -1) if [ ! -s "$BACKUP_DIR/$LATEST" ]; then echo "ERROR: Backup file is empty!" | mail -s "DB Backup FAILED" [email protected] exit 1 fi echo "Backup successful: $BACKUP_DIR/$LATEST ($(du -h "$BACKUP_DIR/$LATEST" | cut -f1))" #!/bin/bash set -e BACKUP_DIR="/var/backups/postgresql" DATE=$(date +%Y%m%d_%H%M%S) KEEP_DAYS=7 DB_NAME="${1:-all}" # Pass db name or backs up all mkdir -p "$BACKUP_DIR" if [ "$DB_NAME" = "all" ]; then # Backup all databases pg_dumpall -U postgres | gzip > "$BACKUP_DIR/all_${DATE}.sql.gz" else # Backup specific database pg_dump -U postgres -Fc "$DB_NAME" > "$BACKUP_DIR/${DB_NAME}_${DATE}.dump" fi # Remove backups older than KEEP_DAYS find "$BACKUP_DIR" -type f -mtime +$KEEP_DAYS -delete # Verify backup file exists and is not empty LATEST=$(ls -t "$BACKUP_DIR" | head -1) if [ ! -s "$BACKUP_DIR/$LATEST" ]; then echo "ERROR: Backup file is empty!" | mail -s "DB Backup FAILED" [email protected] exit 1 fi echo "Backup successful: $BACKUP_DIR/$LATEST ($(du -h "$BACKUP_DIR/$LATEST" | cut -f1))" #!/bin/bash set -e BACKUP_DIR="/var/backups/postgresql" DATE=$(date +%Y%m%d_%H%M%S) KEEP_DAYS=7 DB_NAME="${1:-all}" # Pass db name or backs up all mkdir -p "$BACKUP_DIR" if [ "$DB_NAME" = "all" ]; then # Backup all databases pg_dumpall -U postgres | gzip > "$BACKUP_DIR/all_${DATE}.sql.gz" else # Backup specific database pg_dump -U postgres -Fc "$DB_NAME" > "$BACKUP_DIR/${DB_NAME}_${DATE}.dump" fi # Remove backups older than KEEP_DAYS find "$BACKUP_DIR" -type f -mtime +$KEEP_DAYS -delete # Verify backup file exists and is not empty LATEST=$(ls -t "$BACKUP_DIR" | head -1) if [ ! -s "$BACKUP_DIR/$LATEST" ]; then echo "ERROR: Backup file is empty!" | mail -s "DB Backup FAILED" [email protected] exit 1 fi echo "Backup successful: $BACKUP_DIR/$LATEST ($(du -h "$BACKUP_DIR/$LATEST" | cut -f1))" chmod +x /usr/local/bin/pg-backup.sh chmod +x /usr/local/bin/pg-backup.sh chmod +x /usr/local/bin/pg-backup.sh -weight: 600;">sudo nano /etc/postgresql/*/main/pg_hba.conf -weight: 600;">sudo nano /etc/postgresql/*/main/pg_hba.conf -weight: 600;">sudo nano /etc/postgresql/*/main/pg_hba.conf local all postgres trust local all postgres trust local all postgres trust # ~/.pgpass # hostname:port:database:username:password localhost:5432:*:postgres:your_password chmod 600 ~/.pgpass # ~/.pgpass # hostname:port:database:username:password localhost:5432:*:postgres:your_password chmod 600 ~/.pgpass # ~/.pgpass # hostname:port:database:username:password localhost:5432:*:postgres:your_password chmod 600 ~/.pgpass -weight: 600;">sudo crontab -e -weight: 600;">sudo crontab -e -weight: 600;">sudo crontab -e # Daily backup at 2 AM 0 2 * * * /usr/local/bin/pg-backup.sh mydb >> /var/log/pg-backup.log 2>&1 # Weekly full backup on Sunday 0 1 * * 0 /usr/local/bin/pg-backup.sh all >> /var/log/pg-backup.log 2>&1 # Daily backup at 2 AM 0 2 * * * /usr/local/bin/pg-backup.sh mydb >> /var/log/pg-backup.log 2>&1 # Weekly full backup on Sunday 0 1 * * 0 /usr/local/bin/pg-backup.sh all >> /var/log/pg-backup.log 2>&1 # Daily backup at 2 AM 0 2 * * * /usr/local/bin/pg-backup.sh mydb >> /var/log/pg-backup.log 2>&1 # Weekly full backup on Sunday 0 1 * * 0 /usr/local/bin/pg-backup.sh all >> /var/log/pg-backup.log 2>&1 -weight: 600;">sudo nano /usr/local/bin/mysql-backup.sh -weight: 600;">sudo nano /usr/local/bin/mysql-backup.sh -weight: 600;">sudo nano /usr/local/bin/mysql-backup.sh #!/bin/bash set -e BACKUP_DIR="/var/backups/mysql" DATE=$(date +%Y%m%d_%H%M%S) KEEP_DAYS=7 MYSQL_USER="backup_user" MYSQL_PASS="${MYSQL_BACKUP_PASSWORD}" # Set as env var in cron mkdir -p "$BACKUP_DIR" # Get all databases DATABASES=$(mysql -u "$MYSQL_USER" -p"$MYSQL_PASS" -e "SHOW DATABASES;" | grep -Ev "(Database|information_schema|performance_schema|sys)") for DB in $DATABASES; do mysqldump -u "$MYSQL_USER" -p"$MYSQL_PASS" --single-transaction --routines --triggers "$DB" | gzip > "$BACKUP_DIR/${DB}_${DATE}.sql.gz" echo "Backed up: $DB" done find "$BACKUP_DIR" -type f -mtime +$KEEP_DAYS -delete echo "Backup complete. Files in $BACKUP_DIR" #!/bin/bash set -e BACKUP_DIR="/var/backups/mysql" DATE=$(date +%Y%m%d_%H%M%S) KEEP_DAYS=7 MYSQL_USER="backup_user" MYSQL_PASS="${MYSQL_BACKUP_PASSWORD}" # Set as env var in cron mkdir -p "$BACKUP_DIR" # Get all databases DATABASES=$(mysql -u "$MYSQL_USER" -p"$MYSQL_PASS" -e "SHOW DATABASES;" | grep -Ev "(Database|information_schema|performance_schema|sys)") for DB in $DATABASES; do mysqldump -u "$MYSQL_USER" -p"$MYSQL_PASS" --single-transaction --routines --triggers "$DB" | gzip > "$BACKUP_DIR/${DB}_${DATE}.sql.gz" echo "Backed up: $DB" done find "$BACKUP_DIR" -type f -mtime +$KEEP_DAYS -delete echo "Backup complete. Files in $BACKUP_DIR" #!/bin/bash set -e BACKUP_DIR="/var/backups/mysql" DATE=$(date +%Y%m%d_%H%M%S) KEEP_DAYS=7 MYSQL_USER="backup_user" MYSQL_PASS="${MYSQL_BACKUP_PASSWORD}" # Set as env var in cron mkdir -p "$BACKUP_DIR" # Get all databases DATABASES=$(mysql -u "$MYSQL_USER" -p"$MYSQL_PASS" -e "SHOW DATABASES;" | grep -Ev "(Database|information_schema|performance_schema|sys)") for DB in $DATABASES; do mysqldump -u "$MYSQL_USER" -p"$MYSQL_PASS" --single-transaction --routines --triggers "$DB" | gzip > "$BACKUP_DIR/${DB}_${DATE}.sql.gz" echo "Backed up: $DB" done find "$BACKUP_DIR" -type f -mtime +$KEEP_DAYS -delete echo "Backup complete. Files in $BACKUP_DIR" CREATE USER 'backup_user'@'localhost' IDENTIFIED BY 'strong_password'; GRANT SELECT, SHOW VIEW, TRIGGER, LOCK TABLES ON *.* TO 'backup_user'@'localhost'; FLUSH PRIVILEGES; CREATE USER 'backup_user'@'localhost' IDENTIFIED BY 'strong_password'; GRANT SELECT, SHOW VIEW, TRIGGER, LOCK TABLES ON *.* TO 'backup_user'@'localhost'; FLUSH PRIVILEGES; CREATE USER 'backup_user'@'localhost' IDENTIFIED BY 'strong_password'; GRANT SELECT, SHOW VIEW, TRIGGER, LOCK TABLES ON *.* TO 'backup_user'@'localhost'; FLUSH PRIVILEGES; # Install AWS CLI -weight: 600;">sudo -weight: 500;">apt -weight: 500;">install awscli -y aws configure # Add your AWS credentials # Add to backup script aws s3 cp "$BACKUP_DIR/$LATEST" s3://your-backup-bucket/postgresql/ # Or sync entire directory aws s3 sync "$BACKUP_DIR" s3://your-backup-bucket/postgresql/ # Install AWS CLI -weight: 600;">sudo -weight: 500;">apt -weight: 500;">install awscli -y aws configure # Add your AWS credentials # Add to backup script aws s3 cp "$BACKUP_DIR/$LATEST" s3://your-backup-bucket/postgresql/ # Or sync entire directory aws s3 sync "$BACKUP_DIR" s3://your-backup-bucket/postgresql/ # Install AWS CLI -weight: 600;">sudo -weight: 500;">apt -weight: 500;">install awscli -y aws configure # Add your AWS credentials # Add to backup script aws s3 cp "$BACKUP_DIR/$LATEST" s3://your-backup-bucket/postgresql/ # Or sync entire directory aws s3 sync "$BACKUP_DIR" s3://your-backup-bucket/postgresql/ # PostgreSQL restore test pg_restore -U postgres -d test_restore_db /var/backups/postgresql/latest.dump # MySQL restore test gunzip -c /var/backups/mysql/mydb_latest.sql.gz | mysql -u root -p test_restore_db # PostgreSQL restore test pg_restore -U postgres -d test_restore_db /var/backups/postgresql/latest.dump # MySQL restore test gunzip -c /var/backups/mysql/mydb_latest.sql.gz | mysql -u root -p test_restore_db # PostgreSQL restore test pg_restore -U postgres -d test_restore_db /var/backups/postgresql/latest.dump # MySQL restore test gunzip -c /var/backups/mysql/mydb_latest.sql.gz | mysql -u root -p test_restore_db