Tutorials

Moving WordPress Without Plugins; A Manual and Secure Guide

Manually moving WordPress without plugins, from copying files to database dumps and URL replacement with WP-CLI. A final checklist for a migration that doesn't throw errors.

Tutorials

Have you seen the "Error establishing a database connection" error?

Your site works on the previous host, you've pointed the domain to the new server, and now you only see a blank page with that classic error. Or worse: half the page loads and the other half remains empty because the absolute paths in the database still point to the old address. This is precisely the moment when migration plugins fail, and you need to perform the WordPress migration manually.

The good news: this isn't complicated. The bad news: the order of the steps matters more than the steps themselves. One small mistake in URL replacement takes the entire site offline. Read this guide to the end and follow it exactly in that order.

Prerequisites: What do you need?

Before you start, have these tools ready:

  • SSH access to both servers (source and destination) — if you only have cPanel, you can also perform the URL replacement section with WP-CLI from the File Manager, but SSH makes things much easier.
  • Access to phpMyAdmin or the MySQL command line on the destination server.
  • A domain whose DNS points to the new server. If you haven't changed the DNS yet, you can use the /etc/hosts file on your local system to test the site before the official move.

Also check the PHP and MySQL versions. WordPress 6.4 requires PHP 7.2 or higher, but running it on PHP 8.1 or 8.2 is recommended. If the destination host has PHP 5.6, stop and upgrade it first.

Step 1: Copy files with rsync, not FTP

Transferring files with FTP is full of issues: connection drops on large files, loss of file permissions, and slow speeds. Use rsync, which is both faster and preserves permissions and ownership.

rsync -avz --progress /home/user/public_html/ user@new-server:/var/www/html/

The -a flag means archive mode and preserves symlinks, permissions, and timestamps. The -z flag enables compression, which is essential for transfers over the internet. If you have large files such as videos, add the --partial flag so that if the connection drops, it resumes from where it left off.

After it finishes, run rsync once more. This only transfers files that changed during the initial transfer and ensures the final copy is in sync with the source.

This is where people make mistakes: forgetting hidden folders like .htaccess and .user.ini. If you use FTP, you won't see these files and they won't be transferred. The result? The site loads, but permalinks don't work, or you get an error 500. With rsync, this isn't an issue because it transfers all files.

Step 2: Database dump with mysqldump

Now it's the database's turn. On the source server, run this command:

mysqldump -u username -p --single-transaction --quick --lock-tables=false database_name > database_backup.sql

The --single-transaction flag is essential for InnoDB tables; without it, your dump might be inconsistent and copy tables while they are being written to. The --quick flag is also necessary for large databases so that the output is written directly to disk instead of being held in memory.

If your database is large (over 1 GB), compress the output:

mysqldump -u username -p --single-transaction database_name | gzip > database_backup.sql.gz

Then transfer the file to the destination server and import it there:

gunzip -c database_backup.sql.gz | mysql -u username -p database_name

If you haven't created the destination database yet, create it first via cPanel or the CREATE DATABASE command. Also note down the new database username and password; you'll need them in the next step.

Step 3: Edit wp-config.php

On the destination server, open the wp-config.php file and replace these values with the new database information:

define( 'DB_NAME', 'new_database_name' );
define( 'DB_USER', 'new_database_user' );
define( 'DB_PASSWORD', 'new_database_password' );
define( 'DB_HOST', 'localhost' );

The DB_HOST value is usually localhost, but some hosts use a different address such as mysql.example.com. Get this information from your host's database management page.

It's also better to change the Authentication Unique Keys. This logs out all users and invalidates old sessions. You can get these keys from this page.

Step 4: URL replacement with WP-CLI

This is the most important step. If you don't change the site URL, WordPress will load, but all links will point to the old address. Images won't load, menus will break, and if you open the site via the new address, you'll be redirected to the old one.

The wrong method: using a simple SQL query like UPDATE wp_options SET option_value = 'new_url' WHERE option_name = 'siteurl'. This only changes two fields and leaves the rest of the links in the wp_posts, wp_postmeta, and wp_options tables untouched.

The right method: WP-CLI. If you have SSH access to the destination server, run this command from the WordPress root folder:

wp search-replace 'http://old-domain.com' 'http://new-domain.com' --all-tables --precise

The --all-tables flag scans all WordPress tables, not just the default ones. If you have plugins installed that have their own tables (like WooCommerce or Yoast), this flag is essential. The --precise flag also prevents incorrect replacement of strings that are part of a larger word.

If WP-CLI isn't installed on the server, you can use the Search Replace DB script. Upload this script to the root folder, run it from the browser, and after it finishes, be sure to delete it. This file is a serious security vulnerability if it remains on the server.

Another alternative: temporarily install the "Better Search Replace" plugin, perform the replacement, and then delete the plugin. This method works for those who don't have SSH access, but remember to remove the plugin.

This is where people make mistakes: forgetting http versus https. If the previous site worked over HTTPS and the new site also has HTTPS, the replacement string must exactly include https://. If you only replace http://old-domain.com, links stored with https:// will remain untouched, and half the site will break.

Step 5: Post-migration checklist

The file and database transfer is done. Now it's time to verify. Run this checklist in order:

  1. Open the site's homepage. If you get an error 500, check the wp-config.php file and add define( 'WP_DEBUG', true ); to see the actual error.
  2. Open a post and a page and make sure permalinks work correctly. If you get a 404, go to the permalink settings and save again so the .htaccess file is rewritten.
  3. Open an image from the media library and check its address. If it points to the old domain, redo the URL replacement step.
  4. Create a new post and publish it. This ensures the database is writable and WordPress cron jobs work correctly.
  5. Test the contact form or any other form. If it uses SMTP, also check the email settings.
  6. Check the site with a website speed test. If the TTFB is high, you probably haven't enabled caching on the destination server or PHP-FPM isn't optimally configured.

After these checks, if everything is fine, change the DNS. If you changed the DNS before the migration and are testing the site via the new address, make sure your local DNS cache is cleared.

Moving from shared hosting to dedicated Linux hosting

If you're moving from shared hosting to Linux hosting or a virtual server, there's one important difference: file ownership. On shared hosting, files usually belong to your user. On a virtual server, you need to make sure the files belong to the user that PHP runs as (usually www-data or the cPanel user).

chown -R www-data:www-data /var/www/html/

If you don't do this, WordPress might not be able to write files, and you'll encounter a "Permission denied" error when uploading images or installing plugins.

Moving WordPress with a large database; a rarely mentioned tip

If your database is over 2 GB, the standard dump and import method might hit a timeout error. In this case, instead of dumping the entire database, dump the tables separately:

mysqldump -u username -p --single-transaction database_name wp_posts wp_postmeta > content_tables.sql

Then dump the remaining tables in a separate dump. This allows you to isolate errors, and if a table has an issue, you only need to transfer that one again.

Frequently Asked Questions

Is moving WordPress without plugins safe?

Yes, if you follow the steps in the correct order. The main risk is in URL replacement, which is minimized with WP-CLI and the --precise flag. Migration plugins sometimes create hidden errors that only appear after a few weeks; a manual migration is more transparent.

After the move, the site redirects to the old domain. What's the problem?

You haven't completed the URL replacement. Run the wp search-replace command again and make sure you've covered both http:// and https://. Also clear the browser cache and DNS cache.

Error 500 after WordPress migration; where do I start?

First, check the wp-config.php file and add define( 'WP_DEBUG', true );. You'll see the actual error. The most common cause is incorrect file permissions or a PHP version mismatch. If no error is displayed, temporarily delete the .htaccess file.

Can I test the site before changing the DNS?

Yes. Edit the /etc/hosts file on your local system and map the new server's IP address to your domain. This way, only from your system will the site load with the new domain, while other users will still see the previous host.

ServerNet Support

ServerNet engineering & editorial team — specialists in infrastructure, networking and web hosting.

WordPress Hosting
Share:

Comments 0

No comments yet — be the first!

Leave a comment

Related service

WordPress Hosting

A purpose-built WordPress stack on LiteSpeed Enterprise and NVMe — auto-install, secure updates, staging and caching that keeps you on top of Google.