Magento 2 Backup and Restore: What to Save and How
A backup is only useful if you can restore it, quickly, under pressure, onto a server that may not be the original one. Many Magento stores have backups that fail that test: a database dump without the encryption key, media that was never copied, or a dump that errors halfway through the import because of trigger definers.
This article covers what a complete Magento 2 backup contains, how to create each part, and how to restore it. It applies to Magento Open Source and Adobe Commerce on your own servers. Adobe Commerce Cloud has its own snapshot and backup tooling, which I do not cover here.
Do not rely on the built in backup
Magento has a backup feature in the admin and the setup:backup command. Adobe deprecated it years ago and it is disabled by default in configuration. It runs inside PHP, is slow on large databases, stores the result on the same server and was never meant for production disaster recovery. Use database and file tools directly instead.
What a complete backup contains
| Part | Why it matters |
|---|---|
| Database | Products, customers, orders, configuration, CMS content |
| pub/media | Product images, category images, CMS uploads, downloadable products |
| app/etc/env.php | Database credentials and the encryption key |
| Code | Git repository plus composer.json and composer.lock |
| Custom data folders | Import and export files, feeds, files written by extensions |
| Server configuration | Nginx, PHP-FPM, cron, Varnish, Redis settings |
The encryption key deserves its own line. Magento encrypts payment gateway keys, API passwords and other secrets in core_config_data with the key stored in env.php. A database backup without the matching env.php restores a store where all of those values are unreadable. Keep a copy of env.php with every backup, encrypted, because it contains secrets. More about that file in the env.php and config.php guide.
You do not need to back up generated, pub/static, var/cache or var/page_cache. Those are rebuilt from code. The search index in OpenSearch and the content of Redis are also rebuilt, by reindexing and by normal traffic.
Database dump that restores cleanly
For a consistent dump of InnoDB tables without locking the store, use a single transaction:
mysqldump \
--single-transaction \
--quick \
--routines \
--triggers \
--no-tablespaces \
-h db-host -u backup_user -p magento \
| sed -E 's/DEFINER=`[^`]+`@`[^`]+`//g' \
| gzip > magento-$(date +%Y%m%d-%H%M).sql.gz
--single-transactiongives a consistent snapshot without blocking writes. It works for InnoDB, which is what Magento uses.--quickstreams rows instead of buffering whole tables in memory.--triggersmatters because Magento uses triggers for indexers in Update by Schedule mode.- The sed command removes
DEFINERclauses from triggers. Without it, importing on a server where that database user does not exist fails, or needs elevated privileges.
On MariaDB the client is called mariadb-dump in recent versions, with the same options.
A word of caution on partial dumps. By default, mysqldump writes a DROP TABLE IF EXISTS before each table. If you dump only some rows of a table, with --where for example, and import that file into an existing database, the table is dropped and replaced by the partial data. Know what a dump file contains before importing it anywhere that matters.
For larger databases, physical backup tools such as Percona XtraBackup or Mariabackup are faster to restore than a logical dump. They copy the data files while the server runs. The tradeoff is that the restore must go to a compatible database server version.
Point in time recovery
A nightly dump means you can lose up to a day of orders. If that is not acceptable, enable binary logs on the database server and keep them with your backups. Restoring the last full dump and replaying binary logs up to a given moment lets you recover to just before a bad deploy or an accidental delete. Binary logs grow quickly on busy stores, so set an expiry period and watch disk usage.
Media and other files
Media is usually the largest part of the backup and changes slowly, so incremental copies work well:
rsync -a --delete \
--exclude 'catalog/product/cache/' \
/var/www/shop/shared/pub/media/ \
backup-host:/backups/shop/media/
The product image cache can be excluded because Magento regenerates it, or you can rebuild it after a restore with bin/magento catalog:images:resize. Use a backup tool with versioning, such as restic or borg, if you need to recover a file deleted several days ago. A plain rsync with --delete only keeps the latest state.
Where to keep backups
- Off the server. A backup on the same disk does not survive a disk failure, a deleted server or ransomware.
- Encrypted. The database holds customer data and env.php holds secrets.
- With retention. Daily copies for a couple of weeks and weekly copies for a few months covers most needs. Some problems, like a malware injection, are discovered weeks after they started. See the malware cleanup checklist.
- With restricted access. The server that creates backups should be able to write but not delete old ones, so a compromised server cannot erase its own history.
Restoring a store
The order matters. A restore that starts cron too early can send emails or sync orders against a half imported database.
- Stop cron for the Magento user and stop queue consumers.
- Create an empty database and import the dump:
gunzip < magento-20260110-0300.sql.gz | mysql -h db-host -u magento -p magento - Deploy the code at the matching commit and run
composer install. - Restore app/etc/env.php, then update database credentials if they changed. Keep the original encryption key.
- Restore pub/media and custom data folders.
- If the domain changed, update the base URLs:
For multi website setups, check the website and store view scopes in core_config_data too.bin/magento setup:store-config:set --base-url="https://new.example.com/" --base-url-secure="https://new.example.com/" - Compile, deploy static content, reindex and flush cache:
bin/magento setup:di:compile bin/magento setup:static-content:deploy -f bin/magento indexer:reindex bin/magento cache:flush - Check the store, then start cron and consumers.
If you restore to a non production environment, sanitize the data before anyone uses it, and disable outgoing email and integrations. See how to sanitize a Magento database for staging.
Test the restore
Schedule a restore test, at least every few months, onto a separate server. Measure how long it takes. That number is your real recovery time, and it is often much longer than people assume, because importing a large database and reindexing takes time. Write the steps down while you do it, so the next restore is done from a document and not from memory.
FAQ
Should I use bin/magento setup:backup?
No. The built in backup is deprecated, disabled by default and not suited to production. Use mysqldump or a physical backup tool for the database and rsync or restic for files.
Why is the encryption key so important for backups?
Magento encrypts secrets such as payment API keys with the key in app/etc/env.php. Without the same key, a restored database has unreadable credentials.
Why does my Magento dump fail to import with a DEFINER error?
Indexer triggers carry the database user that created them. Remove the DEFINER clauses with sed when creating the dump, or create the same user on the target server.
Do I need to back up the OpenSearch index?
No. It is rebuilt from the database with bin/magento indexer:reindex. Back up the database and media, then reindex after restoring.
I am available for freelance Magento and Adobe Commerce work, including backup and recovery setups. If you need help with this, get in touch.
Related articles
Magento 2 RabbitMQ Consumers That Don't Die Silently
Set up RabbitMQ message queues in Magento 2.4 the right way: queue XML files, consumers run by cron or supervisor, max-messages and how to spot a dead consumer.
Zero Downtime Magento 2 Deploys on a Single Server
A practical zero downtime deploy for Magento 2.4 on one server: build in a release folder, compile outside live, switch a symlink and roll back in seconds.
Sanitize a Magento 2 Database for Staging and Local Dev
How to copy a Magento 2 production database to staging safely: anonymize customer and order data, disable email and integrations, swap secrets, block indexing.
Magento 2 Admin Security Hardening Checklist
Harden the Magento 2 admin: custom admin path, IP restriction, 2FA, lockout and session settings, user and role cleanup, API integrations and admin logs.