Home/Server & Website Managed Operations/Why WordPress Settings Are Lost During Migration: The Right Way to Handle Serialized Data and Domain Replacement
Server & Website Managed Operations

Why WordPress Settings Are Lost During Migration: The Right Way to Handle Serialized Data and Domain Replacement

A classic failure in WordPress migration is this: files and database are moved, the site loads, but theme settings, widgets, menus, and some plugin configurations revert to defaults.

This isn’t because data was missed or the database corrupted—it’s because the domain replacement method was incorrect. This issue is extremely common in WordPress migrations. It doesn’t throw errors; it silently loses configuration, so many users don’t realize it until long after the migration.

The Root Cause: Serialized Data

WordPress stores a large amount of configuration in the database as PHP serialized strings. The format is “Type:Length:Value“:

a:2:{s:6:"option";s:19:"https://old.com/x";s:5:"title";s:5:"Hello";}

Note the number s:19:—it records the length of the following string. When you directly replace old.com with new.com in SQL (assuming the new domain is longer), the string becomes longer, but the length field remains the old value:

Before replacement: s:19:"https://old.com/x"
After replacement:  s:19:"https://new-domain.com/x"   ← Actual length has changed, but recorded as 19

When the length doesn’t match, PHP fails to unserialize the data. WordPress cannot read this configuration entry and thus falls back to default values. This manifests as “lost settings.”

The Wrong Approach

-- Do not use this method to replace domains in WordPress
UPDATE wp_posts    SET post_content = REPLACE(post_content, 'old.com', 'new.com');
UPDATE wp_postmeta SET meta_value   = REPLACE(meta_value,   'old.com', 'new.com');
UPDATE wp_options  SET option_value = REPLACE(option_value, 'old.com', 'new.com');

This SQL looks fine and executes successfully, but it corrupts all serialized data. This is exactly why settings are lost.

The Correct Approach

Using WP-CLI (Recommended)

# First, dry-run to see how many rows will be affected (--dry-run does not modify data)
wp search-replace 'https://old.com' 'https://new.com' --dry-run

# Once confirmed, execute for real
wp search-replace 'https://old.com' 'https://new.com' --all-tables

# Replace only in specific tables
wp search-replace 'old.com' 'new.com' wp_posts wp_postmeta wp_options

# Replace during export (most convenient for migration scenarios)
wp search-replace 'https://old.com' 'https://new.com' --export=dump.sql

wp search-replace automatically updates the length fields within serialized strings, which is its fundamental difference from raw SQL.

If WP-CLI Is Not Available

Use a migration plugin specifically designed to handle serialization (such as Better Search Replace) to perform the replacement. These tools also correct lengths. Alternatively, install the plugin on the new site and execute the replacement via the admin dashboard.

Complete Migration Steps

# ① Export database (with character set to avoid garbled text)
mysqldump -u root -p --default-character-set=utf8mb4 
  --single-transaction --routines --triggers dbname > db.sql

# ② Sync files
rsync -avz -e 'ssh -p 22' /var/www/html/ root@NewIP:/var/www/html/

# ③ Import
mysql -u root -p --default-character-set=utf8mb4 dbname < db.sql

# ④ Replace domain (Critical step, must use search-replace)
wp search-replace 'https://old.com' 'https://new.com' --all-tables

# ⑤ Update site URLs
wp option update siteurl 'https://new.com'
wp option update home    'https://new.com'

# ⑥ Verify: Spot-check a config containing a URL to ensure normal unserialization
wp option get theme_mods_twentytwentyfour

# ⑦ Flush permalinks (Go to Dashboard → Settings → Permalinks and click Save once)
wp rewrite flush

Troubleshooting Commands

# Check how many old domains remain in the database
wp db query "SELECT COUNT(*) FROM wp_posts WHERE post_content LIKE '%old.com%';"

# Check if a specific option can be unserialized normally (PHP side)
php -r 'var_dump(unserialize(file_get_contents("php://stdin")));'

# If table prefix is not wp_
wp config get table_prefix

# View current siteurl / home
wp option get siteurl
wp option get home

Decision Tree

Anomalies After WordPress Migration
├─ Site opens, but settings/menus/widgets are missing
│  └─ Almost certainly due to corrupted serialization → Re-do replacement using wp search-replace
│     (If raw SQL was used previously, restore from backup and restart)
├─ Site does not open (500 Error / Database Connection Error)
│  ├─ wp-config.php credentials not updated → Verify DB_NAME / DB_USER / DB_PASSWORD
│  └─ Table prefix mismatch → Check table_prefix
├─ Homepage works, inner pages return 404
│  └─ Permalinks not configured + need wp rewrite flush
└─ Images not displaying
   ├─ Files not fully transferred → Review uploads directory
   └─ Path case sensitivity → Linux is case-sensitive

Scenario Walkthrough: All Theme Settings Reset to Factory Defaults After Migration

Symptoms: A standard WordPress move is completed. Files are synced, database imported, homepage loads, and articles are present. However, upon entering the backend, you find that theme colors, menus, widgets, and homepage blocks are all gone, as if a new theme were installed.

  1. First, confirm the data actually exists → Query the database directly for the theme configuration record. You will see the data row exists.
    This step is crucial: it rules out “data didn’t migrate” and narrows the problem to “data exists but cannot be read.”
  2. Examine what this data looks like → The content is a serialized string with length markers. The domain inside is still the old one, and the length value was calculated based on the old domain.
  3. Understand why it cannot be read → These strings have built-in length validation. Direct text replacement causes the length to mismatch the actual content. During parsing, the entire segment is deemed invalid, and the program treats it as “no configuration.”
  4. Confirm simple replacement cannot fix it → Data that has already been replaced cannot be salvaged by replacing again, because the lengths are now scrambled. You must start over from a clean backup.
  5. Re-do using a tool that understands serialized formats → Such tools recalculate lengths while replacing text, preventing parsing failures.
  6. Dry-run first to confirm impact scope → See how many rows will change and which tables are involved. Confirm everything is correct before writing to the database.
# Dangerous approach: Only replaces text, ignoring length markers, corrupting serialized data
# UPDATE wp_options SET option_value = REPLACE(option_value,'//old.com','//new.com');

# Correct approach: Use a tool that recalculates lengths
wp search-replace '//old.com' '//new.com' --dry-run --report-changed-only
wp search-replace '//old.com' '//new.com' --report-changed-only

# Target only necessary tables to minimize impact
wp search-replace '//old.com' '//new.com' wp_posts wp_postmeta wp_options --dry-run

Root Cause: Text replacement was used for domain changes without understanding the serialized format. The length markers no longer matched the actual content, causing the entire configuration block to be deemed invalid and fall back to defaults.

Two Key Takeaways:

  • In WordPress migration, never use pure text replacement for domain changes.
    The only criterion for judging if a tool is usable is: Does it simultaneously recalculate the length markers in serialized data?
  • Run a dry run before replacing to clearly see how many rows will change and in which tables.
    This step takes only a few seconds but prevents irreversible mistakes like “replacement scope too broad.”

Comparison of Four Domain Replacement Methods

Method Handles Serialization? Applicable For Risk
SQL REPLACE statement No Pure text fields Breaks serialization length, losing all theme settings
wp-cli search-replace Yes Most scenarios Low (Recommended)
Migration Plugin Yes When unfamiliar with command line Medium (Large databases may timeout)
Modify hosts then change in backend Yes Small sites Medium (Depends on backend availability)

The criterion is simple: Does the replacement tool understand the PHP serialized format? Serialized strings store string lengths. When changing s:7:"old.com" to s:9:"new.com", the length must be updated synchronously. If not, PHP parsing deems it invalid data, manifesting as “theme settings reverting to defaults.”

# Recommended approach: Dry-run first to check impact scope, then write to database
wp search-replace '//old.com' '//new.com' --dry-run --report-changed-only
wp search-replace '//old.com' '//new.com' --report-changed-only

# Replace only in specified tables to avoid collateral damage
wp search-replace '//old.com' '//new.com' wp_posts wp_postmeta wp_options --dry-run

Do not skip the --dry-run step. It tells you how many rows will change and which tables are affected, allowing you to catch issues like “replacement scope too broad” before actually writing to the database.

8 Common Pitfalls

  1. Using SQL REPLACE to change domains: This is the core issue discussed in this article, leading to silent loss of settings.
  2. Not realizing the new domain length has changed: Even if lengths are identical, raw SQL should not be used—because any discrepancy will cause corruption.
  3. Forgetting to replace wp_options: Site configurations and theme settings are stored in this table.
  4. Replacing only http, not https: Different protocols must be handled separately. Run --dry-run first to see the full scope.
  5. Not flushing permalinks: Inner pages return 404. Simply go to the backend and save permalinks again.
  6. Inconsistent table prefixes: Different prefixes in the target database will result in tables not being found. Confirm first with wp config get table_prefix.
  7. Inconsistent character sets: Both export and import must use utf8mb4, otherwise Chinese characters and emojis will break.
  8. Not verifying after replacement: Spot-check a configuration containing a URL using wp option get. It takes 5 seconds to confirm if it’s broken.

Real Customer Feedback (From Cloud Market Reviews and Inquiries for Similar Products)

The following excerpts are taken from real buyer reviews and inquiries for similar operations services on Alibaba Cloud / Tencent Cloud / Huawei Cloud Cloud Markets (service providers include our store and peers, provided here for reference only, not fictitious tickets from our site):

1****n Rating: 5.0 2018-01-04 18:04

45***76 2021-04-14 5.0 Delivered on time. Excellent.

10***02 2024-07-31 5.0 Secure and reliable | Comprehensive features | Affordable price. Prompt handling, migration successful. 10***31 2022-06-22 5.0 Affordable price | Skilled technology | Perfect after-sales service. Good job, helped me migrate my years-old site to a new server.

FREE CHECKUP

Free server checkup

We will send a problem checklist and remediation advice within one business day — no obligation to engage.

135 410 16684
Weekdays Mon – Fri 10:00 – 22:00 (UTC+8) · 7×24 emergency response
Call now
CONTACT

Contact Us

How can we help?

* Required