Migrating a plain WordPress blog is mostly a files-and-database job. Migrating a live WooCommerce store is a different animal — there's an order table that's still getting new rows while you work, a payment gateway that has your old server's IP and webhook URLs hardcoded into its dashboard, and customers who will absolutely notice if their order history disappears. Here's how to move a WooCommerce store to SkyServer without losing a single order or breaking checkout on day one.
Symptom
You've migrated the site the "normal" way — export database, copy files, point DNS — and now one or more of these show up:
- Orders placed in the last few hours (between your database export and the DNS cutover) are missing from WooCommerce > Orders.
- Checkout fails with a generic "error processing checkout" or the payment gateway rejects the transaction outright.
- Stripe or Razorpay webhooks stop updating order status — payments go through, but orders stay stuck on "Pending payment".
- Customers can log in but their past orders show as empty, or "My Account" throws a fatal error.
- Product images or downloadable files return 404 even though the products themselves look fine.
Cause
WooCommerce leans harder on "moving parts that aren't just files" than a typical WordPress site:
- Live order data. Unlike a blog, a store never really has a quiet moment to export the database. Any order placed after your export and before cutover exists only on the old server.
- Payment gateway API keys are often environment-specific. Some gateways (and a lot of self-hosted setups) whitelist the server's outbound IP for API calls. Move the site to a new VPS with a new IP, and the gateway silently rejects requests.
- Webhook URLs point at the old domain or IP. Stripe, Razorpay, PayPal IPN, and most gateways call back to a specific URL to confirm payment. If that URL still resolves to the old server during the transition window, confirmations get lost.
- Serialized data breaks silently. WooCommerce stores a lot of settings and cart/session data as PHP serialized arrays in
wp_optionsandwp_usermeta. A blind SQL find-and-replace on the domain name (instead of a serialization-aware tool) corrupts these rows without throwing an obvious error. - Scheduled Actions and cron-driven stock sync (via Action Scheduler) don't survive a naive file copy if
wp-config.phpcron settings or thewp_actionscheduler_actionstable get out of sync with the new server's clock or cron setup.
Fix
1. Pick a low-order window and freeze writes on the old site
Look at your order history and pick the quietest hour of your quietest day — for most India-facing stores that's somewhere between 2 AM and 5 AM IST. Right before the final export, put the old site into a short maintenance window using a plugin like WP Maintenance Mode, or simply add this to the top of wp-config.php temporarily:
define('WP_MAINTENANCE_MODE_ALLOW_CHECKOUT', false);
Better still, use a plugin that blocks new orders specifically rather than the whole front end, so existing customers browsing don't get a jarring maintenance page during a 10-minute window.
2. Export everything, including Action Scheduler tables
A full cPanel backup or mysqldump should already capture every table, but if you're doing a selective export, explicitly include:
wp_woocommerce_*tables (order lookup, sessions, tax rates, downloadable product permissions)wp_actionscheduler_*tables (queued emails, stock sync, subscription renewals)wp_postmetaandwp_posts(orders are stored as a custom post type unless you've migrated to HPOS — check WooCommerce > Settings > Advanced > Features)
If your store uses WooCommerce's newer High-Performance Order Storage (HPOS), orders live in wp_wc_orders and related tables instead of wp_posts — make sure those are in your dump too. Check under WooCommerce > Settings > Advanced > Features to see which mode you're on before you export.
mysqldump -u dbuser -p --single-transaction dbname > store_export.sql
The --single-transaction flag matters here: it takes a consistent snapshot without locking the tables, so a customer mid-checkout on the old site doesn't get an error while you're exporting.
3. Use a serialization-safe search-replace, not raw SQL
Don't run UPDATE wp_options SET option_value = REPLACE(...) against serialized columns — it breaks the string length prefix inside serialized arrays and corrupts settings silently. Use WP-CLI instead:
wp search-replace 'https://oldstore.com' 'https://newstore.skyserver.in' --all-tables --precise
Run it with --dry-run first to see how many rows will change before committing. This single command is the difference between a clean migration and a store where the cart silently forgets what's in it.
4. Re-issue webhook URLs and re-test the payment gateway before going live
Before you flip DNS, log into your payment gateway's dashboard (Stripe, Razorpay, PayU, whichever you use) and:
- Update the webhook endpoint URL if it references the old domain explicitly rather than a path like
/wc-api/wc_gateway_stripe/ - Check whether your API keys are IP-restricted. If they are, add the new SkyServer VPS's outbound IP to the allowlist before cutover, not after.
- Place one real test transaction (in test/sandbox mode if the gateway supports it) on the new server while it's still only reachable via its temporary URL or a hosts-file override, confirming the order status updates from "Pending" to "Processing" automatically.
Testing checkout via a temporary URL means editing your local computer's hosts file to point your domain at the new server's IP just for your machine, without touching public DNS yet:
# On your local machine, in /etc/hosts (or C:\Windows\System32\drivers\etc\hosts):
203.0.113.10 yourstore.com
5. Do the final sync and cut over DNS
With the old site frozen (Step 1), export the database one last time, import it into the new server, run the search-replace again to catch anything new, and confirm order counts match between old and new before flipping your A record. Keep the old server running and untouched for at least 48 hours after cutover in case you need to pull a missed order or refund reference.
Prevention
| Risk | How to avoid it next time |
|---|---|
| Orders lost during the export window | Always freeze checkout for the final export instead of relying on a "quiet enough" hour |
| Payment gateway silently rejecting requests | Check for IP allowlisting in your gateway dashboard before any server move, not after |
| Corrupted settings/cart data | Always use wp search-replace for domain changes, never raw SQL REPLACE() on serialized columns |
| Missed webhook confirmations | Place a real test transaction on the new server before DNS cutover, not after |
| No rollback path | Keep the old server live and unchanged for 48 hours post-cutover |
If you're moving to a SkyServer VPS rather than shared cPanel hosting, it's also worth setting up automated database backups (cron + mysqldump, or an offsite S3/Wasabi target) immediately after the migration finishes, so the next move — or the next disaster — is a lot less stressful.
Frequently Asked Questions
Do I need to reinstall WooCommerce on the new server?
No. WooCommerce is just a plugin, and it comes across with your regular WordPress files and plugins folder. As long as wp-content/plugins/woocommerce and your theme migrate along with the database, the store configuration comes with it.
What happens to subscription or recurring payments during the migration?
Recurring payments are usually scheduled by the payment gateway itself (Stripe Billing, Razorpay Subscriptions, WooCommerce Subscriptions with Action Scheduler), not by your server's cron in real time. As long as the wp_actionscheduler_* tables migrate correctly and your webhook URL is updated, scheduled renewals should continue uninterrupted. Test one manually if you can before cutover.
Can I migrate with the store still accepting orders the whole time?
You can minimize downtime to a short freeze window (usually under 15 minutes) rather than eliminating it entirely, unless you're set up for database replication between old and new servers. For most stores, a brief checkout freeze during your lowest-traffic hour is the practical trade-off.
My product images show as broken links after migration — why?
This is almost always a leftover hardcoded URL in wp_postmeta or wp_options that the search-replace missed, often because it was serialized inside a different plugin's settings (page builders and gallery plugins are common culprits). Re-run wp search-replace with --all-tables rather than the default tables-only scope.
Should I migrate to HPOS (High-Performance Order Storage) during the move?
Don't combine the two changes. Complete the server migration first, confirm everything works exactly as it did before, and only then consider switching order storage modes as a separate, deliberate change with its own backup.
