When to switch from a plugin to WP-CLI
Course and membership sites accumulate data quickly: lesson activity, quiz attempts, transactions, subscription events and logs. Plugin-based migrations that export through PHP and HTTP can hit time limits, memory limits or upload size caps long before the database is unmanageable. If a plugin migration fails repeatedly at the database step, or the host's import screen rejects the file size, WP-CLI on both servers removes the browser and PHP request limits from the path.
You need SSH access with WP-CLI available on both the old and the new host. Confirm your hosts provide it before cutover day. Run every command from the WordPress root directory, and take a full backup of the destination before importing anything into it.
Measure before you move
wp db size displays the database name and size. With --tables it displays each table name and size instead, and --human-readable shows sizes in readable units. Adding --all-tables lists all tables in the database regardless of prefix, even if not registered with WordPress, which matters because some plugins create tables outside the usual set. Save this output from the old host; it is the first half of your acceptance check.
The per-table list also tells you what is large. Log and analytics tables can sometimes be excluded and rebuilt, while course progress, transaction and subscription tables must move intact. Decide explicitly, in writing, before you exclude anything.
| Command | What WP-CLI documents | Use in a migration |
|---|---|---|
wp db size --tables --human-readable | Displays each table name and size | Baseline on old host; compare after import |
| wp db export - | Exports the database to a file or to STDOUT ('-') | Stream into gzip to cut transfer size |
wp db export --exclude_tables=a,b | Skips the listed tables | Leave out tables you will rebuild, by decision only |
| wp db import - | Imports from a file or from STDIN ('-') | Stream from gunzip on the new host |
| wp db check | Runs mysqlcheck with --check using wp-config credentials | Check tables after import |
wp db query '...' --skip-column-names | Executes a SQL query; flag removes headers | Row counts for key tables |
Export, compress, copy, import
WP-CLI says wp db export exports the database to a file or to STDOUT, and that if the file name is '-' it outputs to STDOUT. It accepts any valid mysqldump flags; its own example uses --skip-opt and --add-drop-table. Writing to STDOUT lets you compress on the fly, for example: wp db export - | gzip > site-db.sql.gz. Copy the compressed file to the new host with scp or rsync over SSH.
On the new host, wp db import imports a database from a file or from STDIN when the file is '-', so the reverse pipe works: gunzip -c site-db.sql.gz | wp db import -. WP-CLI documents a --skip-optimization option that does not disable unique checks and foreign key checks during import, which implies they are disabled by default. If the old and new database prefixes differ, fix that in wp-config.php before importing rather than editing the dump.
Freeze writes on the old site before the final export, so no orders, renewals or lesson completions are created after the dump. Anything recorded after it will not be on the new host.
Verify before search-replace and DNS
Run wp db size --tables on the new host and compare it with the baseline. Sizes can differ slightly after a fresh import because tables are rebuilt, so also compare exact row counts for the tables that matter: users, posts, and the course progress and membership transaction tables your plugins use. wp db query runs SQL against the database, and --skip-column-names removes headers so the output is a bare number you can diff. Then run wp db check, which WP-CLI documents as running mysqlcheck with --check.
Only after counts match should you change URLs. WordPress's migration documentation warns never to change the GUID column and that a naive search-and-replace can break serialized data; the URL search-replace rehearsal guide covers that step in detail, so this guide does not repeat it.
- Users, posts and postmeta counts match the old host.
- Course progress and quiz tables match row for row.
- Membership transaction and subscription tables match row for row.
- wp db check reports success.
- Only then run search-replace, test logins, and schedule DNS.
Files are a separate step
The database is usually the part that defeats plugins, but uploads can be larger. Copy wp-content/uploads with rsync over SSH so a second run transfers only changed files, and run that second pass during the write freeze along with the final database export. Course downloads, certificates and member-only media often live there, so a missing folder shows up as broken lessons, not as an obvious error. Check a sample of protected files as a logged-in member after the move.
Questions before you decide
Does wp db export compress the file itself?
The WP-CLI documentation does not describe a compression option. It does support writing to STDOUT with '-', so you can pipe the output through gzip and pipe gunzip output into wp db import - on the other side.
Why do table sizes differ after import even when nothing is missing?
Imported tables are rebuilt, so on-disk sizes can change. Use exact row counts from wp db query for acceptance, and treat size as a rough check only.
Sources & verification
Product details and prices can change. Check the linked provider before buying.
- WP-CLI: wp db export Accessed 13 Oct 2026
- WP-CLI: wp db import Accessed 13 Oct 2026
- WP-CLI: wp db size Accessed 13 Oct 2026
- WP-CLI: wp db query Accessed 13 Oct 2026
- WP-CLI: wp db check Accessed 13 Oct 2026
- WordPress Advanced Administration: Moving WordPress Accessed 13 Oct 2026
Sources link directly to providers. Product buttons may use separately labeled affiliate links. Read our disclosure.