VPS Snaps

How to back up and restore a PrestaShop store

A PrestaShop backup needs three things: a dump of the MySQL or MariaDB database, an archive of the store directory with img/, download/, upload/, modules and themes, and app/config/parameters.php, which holds the database password and the cookie keys. The back office's DB Backup page covers only the database and leaves the file on the same server. To restore, load all three, clear var/cache, and update the domain if it changed.

10 min readUpdated Checked against official documentation

What to back up, and what to skip

PrestaShop is free, open-source software under the OSL 3.0. This guide covers PrestaShop 8.2 and 9 (the newest releases are 8.2.8 and 9.2.0, from August and September 2026). The store lives in /var/www/shop, PHP runs as www-data, and the back office folder carries the random name it got at install; here admin123abc. ls -d /var/www/shop/admin*/backups shows yours.

PartWhereBack it up?
DatabaseMySQL or MariaDB, named in parameters.phpYes. Products, customers, orders, configuration.
Imagesimg/ (img/p for products, img/c for categories)Yes. Thumbnails can be regenerated, originals cannot.
Virtual products and attachmentsdownload/Yes. Files customers paid for, stored under md5 names.
Customer uploadsupload/Yes. Files sent for customizable products.
Modules, themes, overridesmodules/, themes/, override/Yes. Paid and edited ones cannot be downloaded again.
parameters.phpapp/config/Yes, on its own and encrypted.
Back office folderadmin123abc/Yes, without backups/ and autoupgrade/.
Cache and logsvar/cache/, var/logs/No. Keep the folders.

The release package ships vendor/, and translations and mail templates may be edited in place, so back up the whole directory minus caches, as PrestaShop's own backup guide does.

The installer writes app/config/parameters.php with the database settings and values generated for this store alone. PrestaShop 8.2 and 9.2 write the same set:

  • cookie_key: PrestaShop 8 and 9 hash passwords with bcrypt, which does not use it. A store upgraded from 1.6 can still hold MD5 hashes salted with cookie_key for customers and employees who have not logged in since; PrestaShop rehashes each one with bcrypt at its next login. Without the original key, those accounts get Authentication failed. until they reset their password.
  • new_cookie_key encrypts the store's cookies and cookie_iv salts their checksum. New values sign everyone out, customers and employees alike.
  • secret is Symfony's secret, described in PrestaShop's template as "A secret key that's used to generate certain security-related tokens".
  • api_public_key and api_private_key are an RSA key pair the installer generates.

None of these can be regenerated to match data that already uses them, so keep the whole file:

Terminal
install -d -m 700 /var/backups/prestashop
Terminal
tar -czf /var/backups/prestashop/shop-params-$(date +%F).tar.gz -C /var/www shop/app/config/parameters.php

A dump plus cookie_key is everything needed to test password guesses against legacy MD5 hashes offline. Store the parameters archive apart from the dumps and encrypt it. PrestaShop also caches a copy in var/cache/prod/appParameters.php, one more reason to leave var/cache out of file backups.

Dump the database with mysqldump

Read the connection settings from parameters.php, which returns a PHP array:

Terminal
php -r '$p = (include "/var/www/shop/app/config/parameters.php")["parameters"]; echo $p["database_host"], " ", $p["database_port"], " ", $p["database_name"], " ", $p["database_user"], " ", $p["database_prefix"], PHP_EOL;'

Put the user and password in an option file, so the password stays out of ps:

/etc/mysql/prestashop-backup.cnf
[client]
user=prestashop
password="your-password-here"
host=localhost
Terminal
chmod 600 /etc/mysql/prestashop-backup.cnf
Terminal
mysqldump --defaults-extra-file=/etc/mysql/prestashop-backup.cnf --single-transaction --no-tablespaces prestashop | gzip > /var/backups/prestashop/shop-db-$(date +%F).sql.gz
  • --single-transaction reads InnoDB tables, PrestaShop's default engine, from one consistent snapshot without locking them, so checkout keeps working. PrestaShop's backup guide uses it too.
  • --no-tablespaces avoids the global PROCESS privilege.
  • database_engine in parameters.php names the engine PrestaShop creates tables with. MyISAM tables, from an old install or a module, are not covered by the snapshot; the mysqldump guide shows a query that lists them.

A complete dump ends with a -- Dump completed on line:

Terminal
gunzip -c /var/backups/prestashop/shop-db-2026-10-04.sql.gz | tail -n 1

The back office DB Backup, and its limits

Advanced Parameters > Database > DB Backup still exists in PrestaShop 8.2 and 9.2. It writes a .sql.bz2 file (.sql.gz if PHP lacks the bz2 extension), named after the time and a random number, into admin123abc/backups/. The source shows its limits:

  • Database only. Its own disclaimer says "This function only backs up your database, not your files."
  • Each table is read with a plain SELECT, outside any transaction, so on a busy store the tables come from slightly different moments.
  • Only tables with the store's prefix are included. "Ignore statistics tables" leaves out the rows of connections, connections_page, connections_source, guest and statssearch.
  • The file stays on the store's own server. There is no schedule and no restore button; the page's help walks you through importing it with phpMyAdmin.

It is fine for a quick copy before a change. For the backups you depend on, use mysqldump and copy the result off the server.

Maintenance mode, and orders between backups

Nightly dumps need no maintenance mode. Close the store for the final backup before a move, so no order arrives between the last dump and the switch:

Terminal
sudo -u www-data php /var/www/shop/bin/console prestashop:config set PS_SHOP_ENABLE --value 0

That is the Enable store switch in Shop Parameters > General > Maintenance; visitors get a 503 maintenance page, and IP addresses in PS_MAINTENANCE_IP can still browse. Without --shopId it applies to all shops. The switch is stored in the configuration table, so a dump taken with the store closed restores closed; PrestaShop's post-restore checklist starts with turning maintenance mode off.

A restore loses every order placed after the dump it comes from. The WooCommerce guide works through how many orders each backup interval puts at risk and how to keep the ones in the gap; the reasoning is the same here. Before loading an older dump over a damaged store, save the current database and list the orders placed since the backup. date_add is in the store's time zone, set in International > Localization:

Terminal
mysql --defaults-extra-file=/etc/mysql/prestashop-backup.cnf prestashop -e "SELECT id_order, reference, total_paid_tax_incl, date_add FROM ps_orders WHERE date_add > '2026-10-04 03:10:00' ORDER BY id_order" > /root/orders-since-backup.tsv

Archive the store files

Dump the database first, then the files, so the database never points at an image the archive lacks:

Terminal
tar -czf /var/backups/prestashop/shop-files-$(date +%F).tar.gz --exclude='shop/app/config/parameters.php' --exclude='shop/var/cache/*' --exclude='shop/var/logs/*' --exclude='shop/admin123abc/backups/*' --exclude='shop/admin123abc/autoupgrade/*' -C /var/www shop
  • parameters.php has its own archive. var/cache and var/logs are rebuilt or disposable; the /* keeps the folders themselves.
  • backups holds the back office's database copies, and autoupgrade is the Update Assistant's scratch folder, which can hold full copies of the store.
  • Exclude patterns match the stored names and must come before the directory.

A large img/ makes a full archive every night heavy. restic or rsync send only changed files.

Restore on a new server

Install a web server, MySQL 5.7 or MariaDB 10.2 or later, and a PHP version your release supports: PrestaShop 9.0 runs on PHP 8.1 to 8.4 and 9.1 adds 8.5. Create an empty database and user:

MySQL / MariaDB prompt
CREATE DATABASE prestashop CHARACTER SET utf8mb4;
CREATE USER 'prestashop'@'localhost' IDENTIFIED BY 'your-password-here';
GRANT ALL PRIVILEGES ON prestashop.* TO 'prestashop'@'localhost';
Terminal
tar -xzf /var/backups/prestashop/shop-files-2026-10-04.tar.gz -C /var/www
Terminal
tar -xzf /var/backups/prestashop/shop-params-2026-10-04.tar.gz -C /var/www

Edit database_host, database_name, database_user and database_password in parameters.php if they changed. Keep every key exactly as it is. Then delete the cache:

Terminal
rm -rf /var/www/shop/var/cache/prod /var/www/shop/var/cache/dev

PrestaShop reads its parameters from var/cache/prod/appParameters.php and refreshes that copy only when parameters.php is newer. tar restores parameters.php with its old modification time, so a leftover cache from a fresh install would win. Load the dump and give the files to the PHP user:

Terminal
gunzip -c /var/backups/prestashop/shop-db-2026-10-04.sql.gz | mysql --defaults-extra-file=/etc/mysql/prestashop-backup.cnf prestashop
Terminal
chown -R www-data:www-data /var/www/shop

Change the domain

PrestaShop keeps its address in the database: domain, domain_ssl and physical_uri in the shop_url table, and PS_SHOP_DOMAIN and PS_SHOP_DOMAIN_SSL in configuration. The front office redirects any host name it does not know to the stored domain (a 302 with the default settings), while the back office answers on any host name.

So the simplest fix is in the back office: Shop Parameters > Traffic & SEO > SEO & URLs > Set shop URL. Saving it updates all four values and rewrites .htaccess, whose rewrite rules name the domain on Apache. From the command line, update the tables yourself, using your table prefix:

MySQL / MariaDB prompt
UPDATE ps_shop_url SET domain = 'shop.example.net', domain_ssl = 'shop.example.net' WHERE id_shop = 1 AND main = 1;
UPDATE ps_configuration SET value = 'shop.example.net' WHERE name IN ('PS_SHOP_DOMAIN', 'PS_SHOP_DOMAIN_SSL');

With several shops, each has its own shop_url rows. Delete var/cache/prod again, then regenerate .htaccess, with the command below on PrestaShop 9.2 and later, or by saving Set shop URL on earlier versions:

Terminal
sudo -u www-data php /var/www/shop/bin/console prestashop:htaccess:generate --force

Verify the restore

Terminal
curl -sS -o /dev/null -w '%{http_code}\n' https://shop.example.net/

Expect 200, or 503 while maintenance mode is on. Compare order counts and the newest order with the live store:

Terminal
mysql --defaults-extra-file=/etc/mysql/prestashop-backup.cnf prestashop -e "SELECT COUNT(*), MAX(date_add) FROM ps_orders"

Log in to the back office, open a product with images, sign in as a test customer, download a virtual product, and run a search. If thumbnails are missing, use Design > Image Settings > Regenerate thumbnails, or on 9.1 and later bin/console prestashop:thumbnails:regenerate all. Then reopen the store:

Terminal
sudo -u www-data php /var/www/shop/bin/console prestashop:config set PS_SHOP_ENABLE --value 1

Testing restores explains how to repeat this on a schedule.

Automate it with cron

This script writes under temporary names, checks the dump, and only then renames. tar exits with 1 when a file changed while it was read, so 1 counts as success.

/usr/local/bin/prestashop-backup.sh
#!/bin/bash
set -euo pipefail

SHOP_DIR="/var/www"
SHOP="shop"
ADMIN="admin123abc"
DB_NAME="prestashop"
BACKUP_DIR="/var/backups/prestashop"
KEEP_DAYS=14
STAMP="$(date +%Y-%m-%d_%H%M)"
DB="$BACKUP_DIR/$SHOP-db-$STAMP.sql.gz"
FILES="$BACKUP_DIR/$SHOP-files-$STAMP.tar.gz"

mkdir -p "$BACKUP_DIR"
trap 'rm -f "$DB.partial" "$FILES.partial"' EXIT

mysqldump --defaults-extra-file=/etc/mysql/prestashop-backup.cnf \
  --single-transaction --no-tablespaces "$DB_NAME" | gzip > "$DB.partial"
gunzip -c "$DB.partial" | tail -n 1 | grep -q "Dump completed"
mv "$DB.partial" "$DB"

tar -czf "$FILES.partial" \
  --exclude="$SHOP/app/config/parameters.php" \
  --exclude="$SHOP/var/cache/*" --exclude="$SHOP/var/logs/*" \
  --exclude="$SHOP/$ADMIN/backups/*" --exclude="$SHOP/$ADMIN/autoupgrade/*" \
  -C "$SHOP_DIR" "$SHOP" || [ $? -eq 1 ]
mv "$FILES.partial" "$FILES"

find "$BACKUP_DIR" -type f \( -name "$SHOP-db-*" -o -name "$SHOP-files-*" \) -mtime +"$KEEP_DAYS" -delete
Terminal
chmod 755 /usr/local/bin/prestashop-backup.sh
/etc/cron.d/prestashop-backup
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

10 3 * * * root flock -n /run/lock/prestashop-backup.lock /usr/local/bin/prestashop-backup.sh >> /var/log/prestashop-backup.log 2>&1

A store taking orders all day should dump the database far more often than it archives files, as the WooCommerce guide explains; binary log point-in-time recovery closes the gap further. Copy everything off the server, for example with rclone, and see the cron guide for logging and alerts.

Common errors

ErrorFix
The store shows Oops, something went wrong. and var/logs/ holds Link to database cannot be established: followed by the server's reasonThe database settings in parameters.php are wrong for this server, or the user has no grant. Fix them and delete var/cache/prod.
Unable to write in the "cache" directory followed by a pathPHP cannot write to var/cache. Give var/ to the PHP user.
Changes to parameters.php seem ignoredA stale var/cache/prod/appParameters.php wins. Delete var/cache/prod.
The store redirects to the old domainUpdate shop_url and PS_SHOP_DOMAIN, PS_SHOP_DOMAIN_SSL, then clear the cache.
Every page but the home page returns 404 on Apache.htaccess still names the old domain in its rewrite conditions. Regenerate it.
Some customers get Authentication failed. with the right passwordLegacy MD5 hashes need the original cookie_key. Restore the original parameters.php, or have them reset their password.
Everyone was signed outnew_cookie_key or cookie_iv changed, or the domain did. Expected after a domain change.
The front office shows the maintenance pageThe dump was taken with the store closed. Set PS_SHOP_ENABLE to 1.
Access denied; you need (at least one of) the PROCESS privilege(s) for this operationAdd --no-tablespaces to mysqldump.

Moving the store to another provider? See moving a server to a new provider.

Frequently asked questions

Does PrestaShop's DB Backup back up the whole store?
No. Advanced Parameters > Database > DB Backup saves only the database, table by table without a transaction, into the back office folder on the same server. Images, downloads, modules, themes and parameters.php need a separate file backup.
What happens if I lose the PrestaShop cookie key?
Passwords hashed with bcrypt, which PrestaShop 8 and 9 use, keep working. Legacy MD5 hashes from 1.6-era accounts that have not logged in since fail until the person resets the password. A new new_cookie_key or cookie_iv signs everyone out.
Do I need maintenance mode to back up PrestaShop?
Not for mysqldump --single-transaction, which reads InnoDB tables from one snapshot while the store takes orders. Close the store only for the final backup before a move.
Where does PrestaShop store product images and downloads?
Product images are in img/p, category images in img/c, virtual products and attachments in download, and customer uploads for customizable products in upload.

How this was checked

Commands, limits and prices were checked against these official pages, on October 4, 2026: