• Skip to primary navigation
  • Skip to main content
  • Skip to primary sidebar
  • Skip to secondary sidebar
OpenTechTips

OpenTechTips

Practical IT Guides, Expert Tips, and Real-World Solutions

MENUMENU
  • HOME
  • ALL TOPICS
    • Exchange
    • InfoSec
    • Linux
    • Networking
    • Scripting
      • PowerShell
    • SSL
    • Tools
    • Virtualization
    • Web
    • Windows
  • ABOUT
  • SUBSCRIBE
Home ยป WordPress backup for free!

WordPress backup for free!

July 25, 2026 - by Zsolt Agoston - last edited on July 25, 2026

A reliable backup gives you a way back when an update fails, a file is deleted, or the database is damaged. This guide builds a simple backup system using standard Linux tools, so it does not require a paid WordPress backup service.

The finished script creates a complete site archive that contains both the WordPress files and a fresh database export. It also verifies the archive before treating it as a completed backup and automatically removes older copies.

What this setup does

  • Exports the WordPress database.
  • Stores the SQL export inside the WordPress folder.
  • Creates one compressed archive containing the full site and SQL export.
  • Checks that the archive can be read.
  • Keeps the 10 newest backups.
  • Runs automatically through cron.

Each run produces one dated .tar.gz file. Keeping the database export and site files together makes it easier to identify which files and database snapshot belong to the same backup.

This guide assumes:

  • WordPress is stored in /var/www/SITE_NAME
  • The database name is the same as SITE_NAME
  • Backups are stored in /backup
  • The script runs as root

Replace all example names with your own values.

Run the commands from a root shell unless a step says otherwise. Before using the script on a production server, confirm the WordPress path, database name, MySQL account, and intended archive owner.

1. Create the backup folder

Run:

The backup directory is kept outside the website's document root. Mode 700 allows only root to enter the directory or list its contents.

mkdir -p /backup
chmod 700 /backup

2. Create a MySQL login file

mysqldump needs database credentials, but placing the password on the command line or directly in the script can expose it. A separate, permission-protected client file keeps the script reusable and limits who can read the credentials.

Create:

/root/.mysql-SITE_NAME.cnf

Add:

[client]
user=MYSQL_USER
password=MYSQL_PASSWORD
host=localhost

Protect the file:

chmod 600 /root/.mysql-SITE_NAME.cnf

Do not place the password directly inside the backup script.

Use a MySQL account with only the permissions required to read and export this site's database. Never share the login file or include it in the site archive.

3. Create the backup script

The script stops when a command fails, creates the database export, compresses the entire WordPress directory, tests the temporary archive, and only then moves it into place as the finished backup. This prevents an obviously unreadable archive from being mistaken for a successful backup.

Create:

/root/wordpress-backup.sh

Add:

#!/usr/bin/env bash

set -Eeuo pipefail

site="SITE_NAME"
webroot="/var/www/$site"
backup_dir="/backup"
sql_dir="$webroot/sqlbackup"
sql_file="$sql_dir/$site.sql"
archive_owner="BACKUP_USER:BACKUP_GROUP"

backup_file="$backup_dir/${site}_$(date +%F).tar.gz"
temporary_file="${backup_file}.tmp"

mkdir -p "$backup_dir" "$sql_dir"

mysqldump 
    --defaults-extra-file="/root/.mysql-$site.cnf" 
    --single-transaction 
    --quick 
    --no-tablespaces 
    "$site" > "$sql_file"

tar -C "$webroot" -czf "$temporary_file" .

tar -tzf "$temporary_file" > /dev/null

chmod 600 "$temporary_file"
chown "$archive_owner" "$temporary_file"

mv "$temporary_file" "$backup_file"

mapfile -t backups < <(
    printf '%sn' "$backup_dir"/"${site}"_*.tar.gz | sort -r
)

if (( ${#backups[@]} > 10 )); then
    rm -f -- "${backups[@]:10}"
fi

Replace:

  • SITE_NAME with the WordPress folder and database name.
  • BACKUP_USER and BACKUP_GROUP with the account that should own the archives.

How the script works

  1. set -Eeuo pipefail makes the script stop on errors, unset variables, and failed pipeline commands.
  2. mysqldump creates a transactionally consistent SQL export without locking normal InnoDB writes for the duration of the backup.
  3. tar packages the WordPress files and SQL export into a compressed temporary archive.
  4. tar -tzf reads the archive index as a basic integrity check.
  5. The verified temporary file receives restrictive permissions and is renamed to its final dated filename.
  6. The retention section sorts matching archives by filename and deletes everything after the newest 10.

Security note: the SQL export remains in sqlbackup inside the WordPress folder after the script finishes. Ensure your web-server configuration denies all public access to that directory. A database export can contain sensitive site data and must never be downloadable from the website.

4. Protect the script

The script reveals server paths and the location of the MySQL login file. Restricting it to root prevents other local users from reading or changing the backup process.

Run:

chmod 700 /root/wordpress-backup.sh

5. Test the script

Always perform a manual run before scheduling the job. A successful exit alone is not enough: confirm that the expected archive exists and that its file list includes both the website and SQL export.

Run:

/root/wordpress-backup.sh

Check the result:

ls -lh /backup
tar -tzf /backup/SITE_NAME_YYYY-MM-DD.tar.gz | head

The archive should contain the WordPress files and:

./sqlbackup/SITE_NAME.sql

6. Schedule the backup

Cron runs the tested script without manual intervention. Choose a quiet time when server activity is normally low, and select a frequency that matches how often the site changes.

Edit the root crontab:

crontab -e

Example: run every three days at 1:00 AM:

0 1 */3 * * /root/wordpress-backup.sh

This cron expression runs at 1:00 AM on every third day of the month. Because months have different lengths, it does not guarantee an exact 72-hour interval across month boundaries.

Example: run on the first day of every month at 1:00 AM:

0 1 1 * * /root/wordpress-backup.sh

Use a separate script and MySQL login file for each site.

7. Check the scheduled job

A backup plan is useful only when jobs continue to run successfully. Check the archive timestamps after the first scheduled execution and periodically afterward. You should also test a restore on a separate system from time to time.

Show the root cron jobs:

crontab -l

After the next scheduled run, check:

ls -lht /backup

Only the 10 newest archives for each site should remain.

8. Basic restore steps

A restore replaces important production data, so inspect the selected archive in an empty temporary directory first. Confirm that it belongs to the correct site and date before copying files or importing SQL.

Extract the selected archive into an empty folder:

mkdir -p /tmp/wordpress-restore
tar -xzf /backup/SITE_NAME_YYYY-MM-DD.tar.gz 
    -C /tmp/wordpress-restore

Restore the files to the correct WordPress folder only after saving the current site.

Import the database:

mysql 
    --defaults-extra-file="/root/.mysql-SITE_NAME.cnf" 
    SITE_NAME 
    < /tmp/wordpress-restore/sqlbackup/SITE_NAME.sql

Check file ownership and permissions after restoring.

After restoring, test the home page, WordPress administration area, media files, forms, and other important site functions. Keep the pre-restore copy until you have confirmed that the recovered site works correctly.

Important limitation

These archives are stored on the same server. They protect against damaged files, failed updates, and accidental changes, but not against total server or disk loss.

Copy the /backup folder to another machine or remote storage.

Summary

This setup provides a straightforward local backup: it exports the database, archives the full WordPress directory, checks the archive, keeps a limited history, and runs from cron. The most important next step is to copy those archives off the server and periodically prove that you can restore one.

Reader Interactions

Comments Cancel reply

Your email address will not be published. Required fields are marked *

Primary Sidebar

Tools

Secondary Sidebar

CONTENTS

  • What this setup does
  • 1. Create the backup folder
  • 2. Create a MySQL login file
  • 3. Create the backup script
  • How the script works
  • 4. Protect the script
  • 5. Test the script
  • 6. Schedule the backup
  • 7. Check the scheduled job
  • 8. Basic restore steps
  • Important limitation
  • Summary

  • Terms of Use
  • Disclaimer
  • Privacy Policy
Manage your privacy
We use technologies like cookies to store and/or access device information. We do this to improve browsing experience and to show (non-) personalized ads. Consenting to these technologies will allow us to process data such as browsing behavior or unique IDs on this site. Not consenting or withdrawing consent, may adversely affect certain features and functions.
Functional Always active
The technical storage or access is strictly necessary for the legitimate purpose of enabling the use of a specific service explicitly requested by the subscriber or user, or for the sole purpose of carrying out the transmission of a communication over an electronic communications network.
Preferences
The technical storage or access is necessary for the legitimate purpose of storing preferences that are not requested by the subscriber or user.
Statistics
The technical storage or access that is used exclusively for statistical purposes. The technical storage or access that is used exclusively for anonymous statistical purposes. Without a subpoena, voluntary compliance on the part of your Internet Service Provider, or additional records from a third party, information stored or retrieved for this purpose alone cannot usually be used to identify you.
Marketing
The technical storage or access is required to create user profiles to send advertising, or to track the user on a website or across several websites for similar marketing purposes.
  • Manage options
  • Manage services
  • Manage {vendor_count} vendors
  • Read more about these purposes
Manage options
  • {title}
  • {title}
  • {title}
Manage your privacy
To provide the best experiences, we use technologies like cookies to store and/or access device information. Consenting to these technologies will allow us to process data such as browsing behavior or unique IDs on this site. Not consenting or withdrawing consent, may adversely affect certain features and functions.
Functional Always active
The technical storage or access is strictly necessary for the legitimate purpose of enabling the use of a specific service explicitly requested by the subscriber or user, or for the sole purpose of carrying out the transmission of a communication over an electronic communications network.
Preferences
The technical storage or access is necessary for the legitimate purpose of storing preferences that are not requested by the subscriber or user.
Statistics
The technical storage or access that is used exclusively for statistical purposes. The technical storage or access that is used exclusively for anonymous statistical purposes. Without a subpoena, voluntary compliance on the part of your Internet Service Provider, or additional records from a third party, information stored or retrieved for this purpose alone cannot usually be used to identify you.
Marketing
The technical storage or access is required to create user profiles to send advertising, or to track the user on a website or across several websites for similar marketing purposes.
  • Manage options
  • Manage services
  • Manage {vendor_count} vendors
  • Read more about these purposes
Manage options
  • {title}
  • {title}
  • {title}