Change WordPress URLs with wp search-replace
At the end every reference to the old address in the WordPress database (links in posts, settings, widgets and serialized plugin data) will point at the new address, and the home and siteurl settings will match.
What you need before step 1
Applies to: WordPress sites with WP-CLI, for domain changes, HTTP to HTTPS moves and staging to live moves (as documented on developer.wordpress.org)
Admin roles you need
- SSH access to the server as the site's user, with WP-CLI installed
- A database user that can update the WordPress database (the one in wp-config.php)
Licences
None needed.
Install instructions
https://make.wordpress.org/cli/handbook/guides/installing/Our step-by-step →Install stepsReference documentation
https://developer.wordpress.org/cli/commands/search-replace/ReadAlso have ready
- A fresh database backup taken immediately before you start
- The exact old and new addresses, including https:// and with no trailing slash (for example https://old.contoso.com and https://contoso.com)
7 steps
- 1
Back up the database
Where: SSH session, in the WordPress folder (the one containing wp-config.php)WordPress warns to make sure you have a database backup before changing URLs. Export it now.
cd /var/www/contoso.com/public_html wp db export before-search-replace.sqlYou should see: Success: Exported to 'before-search-replace.sql'. - 2
Check the current home and siteurl
Where: The same SSH sessionNote the current values so you know the exact string to search for.
wp option get home wp option get siteurlYou should see: Both print the old address, for example https://old.contoso.com. - 3
Run a dry run
Where: The same SSH session--dry-runruns the whole operation and shows a report without saving changes.--skip-columns=guidleaves the GUID column alone; WordPress says never to change the contents of the GUID column. The command handles PHP serialized data, which a plain find-and-replace on an SQL file would break.wp search-replace 'https://old.contoso.com' 'https://contoso.com' --skip-columns=guid --dry-runYou should see: A table of tables and columns with the number of replacements in each, and a summary line of replacements to be made. Nothing is changed yet. - 4
Decide whether you need --all-tables
Where: The same SSH sessionBy default the command only touches tables registered to WordPress with your table prefix. If plugins created their own tables that also hold the URL, add
--all-tables-with-prefix(tables matching your prefix) or--all-tables(every table in the database, regardless of prefix). Run the dry run again with the flag to compare. On multisite, use--networkfor all sites or--urlto target one.wp search-replace 'https://old.contoso.com' 'https://contoso.com' --skip-columns=guid --all-tables-with-prefix --dry-runYou should see: The report now includes any extra plugin tables that contain the old address. - 5
Run the replacement
Where: The same SSH sessionRun the same command without
--dry-run, keeping any table flag you chose. To produce an SQL file instead of changing the live database (useful when moving to a new server), use--export.wp search-replace 'https://old.contoso.com' 'https://contoso.com' --skip-columns=guid --all-tables-with-prefix wp search-replace 'https://old.contoso.com' 'https://contoso.com' --skip-columns=guid --export=contoso-new.sqlYou should see: The same table as the dry run, followed by a Success line with the number of replacements made. - 6
Catch other forms of the old address
Where: The same SSH sessionContent may also contain the address without the scheme or with http://. Dry-run each variant you find and replace if needed. Keep each pair consistent: no trailing slash on either side.
wp search-replace 'http://old.contoso.com' 'https://contoso.com' --skip-columns=guid --dry-run wp search-replace '//old.contoso.com' '//contoso.com' --skip-columns=guid --dry-runYou should see: Dry runs for the remaining variants report zero, or you replace the ones that are not zero. - 7
Confirm home and siteurl and flush caches
Where: The same SSH session, then a browserWordPress says both settings should include https:// and must not end in a slash. Check them, then clear any caching plugin or host cache and load the site.
wp option get home wp option get siteurl wp cache flushYou should see: Both options print https://contoso.com, and pages load with links pointing to the new address.
Expert tips
--dry-run runs the whole operation and prints the per-table report without saving. Check the numbers make sense: thousands in wp_posts and wp_postmeta is normal, a match in a table you did not expect is a reason to stop and look.
WordPress warns that a plain search and replace can break serialized data, because some values store the string length. wp search-replace handles PHP serialized data correctly; sed or a text editor on the SQL file does not. If some plugin values are not replaced, try --precise, which forces PHP processing for all columns.
wp search-replace 'https://old.contoso.com' 'https://contoso.com' --skip-columns=guid --export=migrated.sql writes the transformed data to an SQL file instead of changing the database. Import that file on the new server and the old site keeps working as your rollback.
Plugins often create tables that are not registered with WordPress. Use --all-tables-with-prefix to include tables with your prefix, and always --skip-columns=guid, because WordPress says never to change the GUID column.
--log and --precise slow the run significantly, and --regex takes about 15 to 20 times longer. Use plain string replacements and run several simple passes (for http://, https:// and // forms) rather than one regular expression.
How to confirm it worked
A final dry run for the old address returns zero replacements:
wp search-replace 'https://old.contoso.com' 'https://contoso.com' --skip-columns=guid --dry-run.Open several pages and the Media Library in a private browser window and check links and images load from the new address.
Log in to wp-admin at the new address and check Settings > General shows the new WordPress Address and Site Address.
How to reverse it
Restore the backup taken in step 1: wp db import before-search-replace.sql, then clear any caches. This replaces the whole database, so any orders, comments or posts created after the backup are lost.
Errors you might see
Widgets, theme settings or page builder layouts lost after a URL changeCause: A find-and-replace was run on the SQL file or with plain SQL, breaking PHP serialized data.
Fix: Restore the backup and redo the change with wp search-replace, which handles serialized data.
GUID column was changed by a search and replace (symptom)Cause: The command was run without --skip-columns=guid.
Fix: Restore the backup and rerun with --skip-columns=guid. WordPress says never to change the GUID column.
Some URLs in a plugin's data were not replacedCause: The plugin's tables are not registered with WordPress, so the default run skipped them. Tables without a primary key are also skipped.
Fix: Rerun with --all-tables-with-prefix or --all-tables (dry run first).
Error establishing a database connectionCause: wp-config.php database settings are wrong for this server.
Fix: Fix DB_NAME, DB_USER, DB_PASSWORD and DB_HOST in wp-config.php, then rerun.
Questions
Can I just edit the SQL file in a text editor?
No. WordPress warns that a search and replace on the whole database can break serialized data. Use wp search-replace, which handles it.
Should I include a trailing slash?
No. Use the address with https:// and no trailing slash on both sides, matching how WordPress stores home and siteurl.
Do I change the GUID column when moving domains?
No. WordPress says never to change the contents of the GUID column. Always add --skip-columns=guid.
How do I do this on multisite?
Use --network to cover all sites, or --url to target one site.
Official sources
Vendors change menus and requirements. Confirm on the source before you rely on a detail. Last checked 4 Nov 2026.
