How to change WordPress URL safely (wp-cli, SQL, and wp-config fallback)
Back to blog

How to change WordPress URL safely (wp-cli, SQL, and wp-config fallback)

6/7/2026 · 2 min · WordPress

Changing WordPress URL sounds simple, but in real migrations, it can break login, media, internal links, plugin callbacks, and cache. In this article, I document the operational method I use to switch domains without improvisation, including validation, content update, and rollback plan.

Concepts that must be clear#

WordPress uses two main options:

In most scenarios, both are identical. In advanced scenarios, they may diverge, but this must be intentional.

Pre-check before changing#

  1. Database backup;
  2. wp-config.php backup;
  3. Inventory of plugins with URL callbacks;
  4. Confirm DNS/SSL for the new domain.
cp wp-config.php wp-config.php.bak.$(date +%F-%H%M)

SQL Export (example):

mysqldump -u DB_USER -p DB_NAME > /root/wp-url-change-$(date +%F-%H%M).sql

Preferred method: wp-cli#

Validate current URL:

wp option get siteurl
wp option get home

Change to new domain:

wp option update siteurl 'https://newdomain.com'
wp option update home 'https://newdomain.com'

Validate again:

wp option get siteurl
wp option get home

Internal reference update#

After changing home/siteurl, there are still hardcoded references in content, metadata, and serialized options. The safe method is wp search-replace.

Dry-run first:

wp search-replace 'https://olddomain.com' 'https://newdomain.com' --all-tables --dry-run

Real application:

wp search-replace 'https://olddomain.com' 'https://newdomain.com' --all-tables

If there is a multisite or custom tables, adjust the scope explicitly.

SQL method (when wp-cli is unavailable)#

Find DB in wp-config.php:

grep DB_ wp-config.php

Connect:

mysql -u DB_USER -p
USE DB_NAME;

Read current values:

SELECT option_name, option_value
FROM wp_options
WHERE option_name IN ('siteurl','home');

Update:

UPDATE wp_options SET option_value='https://newdomain.com' WHERE option_name='siteurl';
UPDATE wp_options SET option_value='https://newdomain.com' WHERE option_name='home';

Update direct references (be careful with serialization):

UPDATE wp_posts SET post_content = REPLACE(post_content, 'https://olddomain.com', 'https://newdomain.com');
UPDATE wp_postmeta SET meta_value = REPLACE(meta_value, 'https://olddomain.com', 'https://newdomain.com');

For serialized options, prefer WP-CLI. Raw SQL can corrupt serialized string lengths.

Emergency fallback via wp-config.php#

When the dashboard becomes inaccessible and you need to recover quickly:

define('WP_HOME', 'https://newdomain.com');
define('WP_SITEURL', 'https://newdomain.com');

This approach forces the URL at runtime. It's useful for incidents but should be treated as temporary.

Post-change validation#

Checklist I execute after changing:

  1. Open frontend (/);
  2. Open admin (/wp-admin);
  3. Test login;
  4. Test media upload;
  5. Test menu links and permalinks;
  6. Clear cache (plugin/CDN/server);
  7. Review browser console for HTTP/HTTPS mixed content.

Real migration troubleshooting#

Login loop on wp-admin#

Common cause: session cookie on the old domain + cache + incorrect HTTPS. Action: clear cookies, clear cache, validate siteurl/home, and HTTPS headers.

Broken css/js#

Common cause: old absolute URLs in plugin/theme. Action: wp search-replace with full scope and review theme options.

Infinite redirect#

Common cause: .htaccess rule + redirect plugin + reverse proxy without correct headers.

Rollback#

If there is a critical impact:

  1. Restore SQL dump;
  2. Restore wp-config.php backup;
  3. Purge cache again;
  4. Reopen the task with a corrected plan.

Production takeaways#

Changing WordPress URL in production requires a process, not an isolated command. When I apply this flow (backup, change, search-replace, validation, and rollback), the migration becomes predictable and auditable with much lower operational risk.

Was this article helpful?

Leave a quick reaction to help prioritize future technical guides:

CC BY-NC

This post is licensed under CC BY-NC.

Comments

Join the discussion below.

0 comments