Database sync
- What happens on
-d - Backups and recovery
- Maintenance mode
- MariaDB and MySQL compatibility
- Large databases
- Table prefixes
- Prefix collisions
What happens on -d
Both directions have the same shape. The source database is only ever read.
| Step | pull -e production -d |
push -e production -d |
|---|---|---|
| 1. Prerequisites | probe local for gzip, mysql, wp; remote for gzip, mysqldump |
probe local for gzip, mysqldump; remote for gzip, mysql, wp |
| 2. Backup the target | local DB to wp-content/local-backup-<ts>.sql.gz |
remote DB downloaded to wp-content/production-backup-<ts>.sql.gz |
| 3. Dump the source | remote mysqldump, gzip, scp down |
local mysqldump, normalise collations, gzip, scp up |
| 4. Import on the target | mysql locally |
mysql on the remote over SSH |
| 5. Adapt on the target | wp search-replace locally for vhost, then wordpress_path |
wp search-replace on the remote for vhost, then wordpress_path |
| 6. Clean up | temp dumps removed | temp dumps removed |
Step 1 aborts with a list of missing programs before anything else happens, so a misconfigured host never leaves a half-done sync.
wp search-replace runs with --all-tables --skip-columns=guid --allow-root, so every table in the target database is adapted, including non-WordPress tables sharing it, and post GUIDs are left alone as WordPress recommends. wp-cli unserializes PHP data properly, so serialized options, widgets and page-builder data survive. --no-adapt skips step 5.
Backups and recovery
Backups are gzipped SQL files in the local wp-content/ folder, named after the target environment and a Unix timestamp. To restore one:
gunzip < wp-content/production-backup-1757400000.sql.gz | mysql -u user -p example # on the remote
gunzip < wp-content/local-backup-1757400000.sql.gz | mysql -u root -p site # locally
If the remote wp search-replace fails after the import, the log names the backup file and the remote is left with the local URLs. Either restore, or re-run wordmove-ng push -d, or run the search-replace by hand on the remote:
wp search-replace 'http://site.test' 'https://example.com' --all-tables --skip-columns=guid --path=/var/www/example
Add wp-content/*.sql.gz to exclude so backups are never synced.
Maintenance mode
global:
maintenance_mode: true
wraps steps 4 and 5 on the target in wp maintenance-mode activate and deactivate, so visitors see the WordPress maintenance page rather than a site pointing at the other environment’s URLs for a few seconds. Deactivation runs even when the adaptation fails. WORDMOVE_MAINTENANCE_MODE=1 forces it on for a single run. Default: off.
MariaDB and MySQL compatibility
mariadbandmariadb-dumpare preferred when present, falling back tomysqlandmysqldump, on each side independently.- Dumps starting with the MariaDB sandbox header
/*!999999- enable the sandbox mode */import cleanly on servers that do not understand it. - Imports run with
--binary-mode,SET FOREIGN_KEY_CHECKS=0and a trailingCOMMIT;, unlessmysql_optionsalready sets binary mode. database.socketanddatabase.portare first-class;--socketinsidemysql_optionsormysqldump_optionsstill works.- Newer
utf8mb3collations (utf8mb3_uca1400_*,utf8mb3_unicode_520_ci) are rewritten toutf8mb4_unicode_ci, andutf8mb3toutf8mb4, before import. Override or extend the mappings:
global:
collation_fallbacks:
utf8mb3_uca1400_ai_ci: utf8mb4_unicode_ci
charset_fallbacks:
utf8mb3: utf8mb4
wpis always called with--allow-root, so root-owned Docker installs work.
Large databases
Pass options straight to the dump and import tools:
database:
mysqldump_options: "--max_allowed_packet=1G --single-transaction --quick --ignore-table=example.wp_actionscheduler_logs"
mysql_options: "--max_allowed_packet=1G"
--hex-blob in mysqldump_options makes binary columns safe to move between servers with different defaults.
Table prefixes
Local and remote must use the same table prefix. wp search-replace --all-tables rewrites values, not table names.
Prefix collisions
If one of the four search terms (local and remote vhost and wordpress_path) is a prefix of another, for example https://site.test and https://site.test.example.com, the replacement of the shorter value also rewrites the longer one. The doctor reports this as an error and the database step warns before running. Use distinct values.