Migrating WordPress Websites

I wrote an article two years ago on how to move your WordPress website, which has been one of my most popular posts.

Over the past two years I’ve found some improvements to my process, most notably around serialized arrays.

Migration Process

  1. Backup the database tables. I like to use Sequel Pro to connect to my database and export them, but you can also use the Adminer WordPress plugin or phpMyAdmin through your server’s cPanel. The default export will the a .sql file, but you might want to use one of the compressed formats. Many hosts only allow you a small file upload (like 2MB), and compressing it can help you stay under that limit.
  2. Backup the wp-content directory. This can be as easy as FTP’ing onto your server and dragging a copy of wp-content/ to your computer. If you have SSH access and are comfortable with command line, I like to make a tarball because it is much faster to download than a lot of small files. Use a command like this: tar -pvczf wp-content.tar.gz wp-content/.
  3. Upload the database to the new server. If WordPress is already installed, use the Adminer plugin to add the database. If not, you might use phpMyAdmin provided by the host. If you’re migrating to a server that’s already running WordPress, it’s a good idea to create a new database and upload the new tables there. That way, if something goes wrong you can quickly switch back to the old site. If you’re limited to one DB, you can also use a different table prefix (here’s how to change the table prefix of your new tables).
  4. UploadΒ Search Replace DB3Β to the top level of your server (wherever wp-config.php is) and run it. Remove it when you’re done. This is used to find all the uses of the old domain and replace them with the new domain. The reason we’re using this tool instead of simply doing it in the database is that it will work with serialized arrays. Click the above link to read more about the problem and solution. If you’re really worried about security, do this locally or on your development server so that this file never has to be on the production server. Alternatively, if your server has WP CLI installed, you can use the wp search-replace command instead of this script.
  5. If a brand new website, upload copy of WordPress along with your custom wp-content directory. If there’s already a WordPress website live, follow the rest of the steps below.
  6. If you’ve downloaded the wp-content folder to your computer, rename the folder wp-content.new. Or if you pulled the tarball over, unpack and name it wp-content.new. The name doesn’t matter, it just has to be different than wp-content. Upload the folder to the same directory that has the old wp-content/ .
  7. Open wp-config.php. Update the DB information and $table_prefix if they have changed.
  8. Save wp-config.php, and then immediately rename wp-content/ to wp-content.old/, and wp-content.new to wp-content/
  9. Check the website’s homepage. If anything looks wrong, switch to the old site while you figure it out. Go into wp-config.php, comment out the new table prefix and remove the commenting on the old table prefix. Rename the wp-content directories back to how they were.
  10. If the site is working, log in and go to Settings > Permalinks, then click Save. This will update the permalink structure and ensure all URLs work.
  11. Go to Settings > Privacy and make sure you have the site visible to search engines.
  12. On the old site, install the Migration Notice plugin. I’ve had a lot of clients get confused about which backend they are supposed to post new content to, so if you aren’t deleting the dev environment immediately this prevents that issue.
  13. Make sure you’ve removed the Search Replace tool. This was mentioned in #4, but deserves reiterating (thanks WPExplorer).
  14. Update file permissions of wp-content directory. If you’re using WPEngine, they’ve added a super useful button “Reset File Permissions” in their WPEngine page of your WordPress backend.

intermediate migration wordpress

Receive New Posts by Email


  1. I’ve been doing so much of this lately, and am still settling on a solid workflow.. I’ve been trialling backupbuddy, (when its good its great, but have found i often have to go back nurse the process depending on (? server config ?)).

    It often seems too much hassle to manage getting SSH access for random short-job clients, so my alternative is to use the cPanel file manager to zip the wp-content directory, ftp the single zip file, then use cpanel to unzip it at the destination..

    I’m developing my themes (using Genesis, Bones4Genesis and Core-Functionality) on XAMPP, and doing this migration to staging servers pretty frequently, and am desperate for a brain-free method of cloning to a remote host (from XAMPP!)… I’m also trying ManageWP, but my apache-fu is not equal to granting access via ports other than 80, etc ..

    Any suggestions for a scriptable process / feedback ?!

    1. The way I outlined is the easiest solution I have found. My only other recommendation is to only develop in one location. You can build the initial version locally, but once you migrate to a staging server for the client to review, continue building it there. It’s just too difficult to keep them all in sync, especially when the client might add content to one and then it disappears when you bring over a newer version.

      You could probably use version control to fix some of this, but that won’t keep the databases in sync and it’s usually overkill for most of my projects.

      1. Thanks.. my workaround is similar to your first response – after the initial clone, I generally only change the theme and a plugin or so, so Transmit sync sorts me out.. then I fix the db when its ready for the client (not ideal!).

        I’m just getting into Git, but my shared hosting absolutely won’t install it.. I’m getting closer to moving to a VPS, but its scary!

        Thanks for your consideration πŸ™‚
        (PS – I don’t see a submit button under this form!)

    1. I don’t work on multisite projects so I’m not much help here, but I would assume the process would be the same.

  2. I used to use the searchreplacedb script, but I found an easier way. I now use the WP Migrate DB plugin.

    it just requires you to enter the old and new domain names and path to root, and does the search/replace and exports the database automatically.
    then you just have to import it to the new DB. Saves a few steps.
    I think, if you have ssh access to both servers, you can transfer the files directly from server to server instead of downloading first

    1. Very cool. I usually only have SFTP access to my development server. If I have it on their server as well I can log in and wget the tarball.

  3. Great walk through Bill! I really like your reasoning about having unique table prefixes. I’ve used unique prefixes for each site for security reasons, but never thought of using as a quick roll back option. It does bring up an issue I’ve thought a little about lately which is merging new and old content. For example on a recent site redesign I needed to keep all the old site’s blog posts and comments, but wanted to replace all the pages, custom posts, menus and widgets… I ended up doing most of that merge manually… probably a better way but hacking it together in MySQL seemed to risky… I don’t know well enough what where everything is that spans multiple tables.

    The one thing about this procedure I do differently is to rename wp-content before I change wp-config… it’s unlikely but the possibility exists for someone to hit /wp-admin and for WordPress to helpfully deactivate the non-existent theme and plugins.

  4. Love that you include the last line – make visible to search engines – I’ve forgotten that MORE than once. So embarrassing!

  5. Bill,

    Great tutorial. One question….You state in item ‘0 or 10?’ to change back to the old prefix if you encounter a problem. So when you change the prefix as described, the old prefix is preserved in the database and then deleted once everything is up and running?


    1. Before you start any work, the old site will be up and running with their old prefix. Migrate a copy of these database tables to your development server, then change the prefix on your dev database. Then build out your new site on the dev server.

      When you’re ready to go live, you are able to upload your new database tables into the old database since they have different prefixes. At this time you’ll have both the original tables and your new site’s tables in the database, and in wp-config.php you’ll tell WordPress which to use. If there’s any issues, you can go back to using the old tables while you figure it out.

      Once the site is up and running smoothly, you can remove the old database tables and the old wp-content directory (renamed to wp-content.old in the above steps).

  6. Hi Bill!

    I’m an aspiring WordPress/Genesis Designer, and I have been trying to wrap my head around this post…

    When you say “Migrating your WordPress Website” are you referring to moving it from your local testing server to and online demo site or your clients temp url?



    1. I typically develop directly on my development server, so the migration process is usually my development server => client’s production server. But if I do decide to develop locally (e.g., at an airport right now developing locally), the migration process is exactly the same going from local installation => my development server.

  7. Dude. That searchreplacedb2.php tool freaking rocks! gonna have to tell the author about that! Good share as usual! Thanks.

  8. hello, i am trying to export from a self hosted wordpress site, to wordpress.com and i find that if i use tools->export on one end and tools->import on other end, many posts are missing.
    I am not sure how to resolve this issue. please help me.

    1. Since you’re going to WordPress.com the only tool you have available is Import/Export. Try exporting in smaller batches, like all the posts from a single year, or from a single category.

  9. Ha! I wish I had your playbook a month earlier, before my back-and-forth attempt to successfully migrate.

    I will definitely be referencing this to all others who are moving thru this “delightful” process πŸ™‚


  10. Backupbuddy is the easiest solution for migrating WordPress.

    If you’re going to do it manually, i think the Velvet Blues plugin is better than search and replace.

    Another option is to change the WordPress Address URL and Site Address Url in Settings > General before you export the database tables, if you’re migrating from a local installation to a web server.

    1. To each his own. After migrating hundreds of site, this is the way that I prefer.

      One quick note though: just changing the WordPress Address URL and Site URL is not enough for a migration. All URLs used throughout the site still need to be updated. This includes nav menu links, images embedded in posts, URLs in widgets (these are serialized so you can’t do a simple find/replace), and many more.

    2. The SQL queries that Bill wrote in the previous article is a better solution than changing the URLs in the wp-admin area. However like he just said this doesn’t fix all the problems, which is why the PHP code linked to in this article is an even better approach.

    3. I second BackupBuddy. Migration can be completed in five minutes start to finish without command line or mySQL knowledge.

  11. Thanks for the step by step, Bill. I’ve been doing this for just about a year now, and after having talked to probably every tech guy at Bluehost, I’ve gotten tons of differing opinions on the best order for completing these steps. I’ll be using this post as a checklist from now on; thanks for simplifying things!

  12. wow, I wonder why i find this after I’m stuck in the quicksand of a less than perfect site migration.
    AND I thought I researched the hell out of it prior to making the first move.
    I have some database prefix issues to clean up – and will be testing this checklist out on future migrations! Thank you for sharing. Not a lot of tech support folks know or are able to spend time on these issues!

    thanks again,

    1. I’ve never used Azure so I’m not sure if there’s any special migration requirements. You might try contacting your hosting provider to see if there’s any host-specific issues.

  13. Searchreplacedb2 is such an awesome script. I can’t even begin to say how much I love it and how much easier it makes migrating a site.

    But for security, super important it’s removed after. Tip 14 should be to make sure that script is removed and your file permissions are set correctly on all the newly uploaded files πŸ˜‰

    Great post!

  14. This worked beautifully the first time I tried it! It’s the first move I’ve done without struggling with lost widgets. Can’t thank you enough for sharing your expertise with us!

  15. hi! thank you for this amazing article! I have got one question: I am not good with databases and afraid to break my blog, can I use an easy way? Like, http://www.cms2cms.com. It migrates website to wordpress for free and no code or tables plus very quickly. Do you know anything about it? And do you suggest I should try?


  16. Thanx Bill. Your article saved me A LOT of time. The search & replace tool especially enabled me to migrate in hours rather in days!

  17. This is a good write-up. Thanks.

    When possible, I highly recommend using rsync to move files from one server to another, rather than sending a tarball. For one thing, it takes fewer steps (a single rsync, vs tar/send/untar). For another thing, it can pick up where it left off, while an enormous tar transfer could die on a crummy connection, and you’d have to start over again. Perhaps most importantly, rsync preserves file masks, including file permissions and any other security layer (like selinux), which can be especially important when your WP install has, eg, custom locations that must be web-writable (like /wp-content/cache or something like that). Of course, this means you’ve got to have SSH access, but I try to avoid working on any projects where I don’t πŸ™‚

    1. I agree, rsync via SSH is definitely preferable, but I estimate only 1-2% of my clients can give me SSH access. Most of my clients use WPEngine for hosting (they don’t provide SSH access), and the ones who do have hosting that allows it usually can’t figure out how to get it for me.

      On most of my projects, the additional work required in obtaining SSH access takes longer than an SSH-based migration would save.

      1. Very cool article. Thanks Bill (for this and all your other resources).
        I’m just in the middle of setting up my whole WP dev set up and workflow (also using WP Engine) and thinking of using git push (instead of SFTP’ing the files).
        What do you think about this / do you use it at all since you’re also on WP Engine?
        (only downside I can think of is for content files not allowed in the WP Engine git push…)

        1. While I love that they offer git push, it only makes sense if you’re already working on a large WPEngine-hosted site. My process of migrating from my dev server to a WPEngine account would be slowed down by git push (I’d have to set up git).

          But I am excited to try it next time I work on a large site that’s hosted with WPEngine.

          1. Got you, thanks. I’m only working on one WP site for a client, with lots of revisions planned so it makes sense for me to use git for managing my codebase. I love the fact that I can do a git push to staging, get the client to review and git push the same commit to prod once they’re happy with it.

  18. Hi Bill,

    I really liked this breakdown of steps. I believe I followed each step correctly, except when I enter in the url of my website, it tags on :8888 and doesn’t display. Do you know why this is? I ran the Search and Replace PHP script, even a couple of times, the first time searching for ‘localhost’ and the second time (and I think actually a third) searching for ‘localhost:8888’ to see if that would stop the browser from automatically appending the :8888 onto the url.

    Thank you again for this article.


    1. Log into phpMyAdmin and go into your wp_options table (or xxx_options, where xxx is your custom table prefix). Look to see what URL is being stored in the database.

  19. Hi Bill.
    Above in 12. Go to Settings > Privacy and make sure you have the site visible to search engines.
    Do you not mean “invisible” to search engines? And, in the latest WordPress (as of this post 3.5.1) it is Settings > Reading > Site Visibility select “Discourage search engines from indexing this site”
    Or, am I missing something here?

    1. Correct, the setting has now moved to Settings > Reading.

      The reason I say “set it to visible” is because I use these instructions go from development site to production site. I have the development site “invisible to search engines”, and when I go back to the live I want to remember to make it visible.

      If you’re going from a live site to a development server, do the reverse – go to Settings > Reading and set it to invisible.

  20. You saved my —! I was migrating a WordPress site, for the first time, for a big client and after the transfer all the pages except for the home page would go back to my dev site. Even the admin! In a frantic search I found the older version of this post and I will tell you, it still works! I added some ticks around column names and straight quotes around strings but other than that, it was the ticket I was looking for. Thanks so much for for that, not sure where I would be right now if I hadn’t found it.

  21. Like one of the other commenters, I normally use a script to migrate from one site to another. For instance the script changes URL and full path (serialized) strings in the database dump. The path being something like ‘/home/username/public_html’.

    In the case of WPEngine, I don’t know what that is. Any ideas?

      1. That request for information took about a day, but I eventually got it from them. Turns out the full path (in my case) is /nas/wp/www/sites//.

        Therefore, when I run my script, I add source/destination URL’s and full path. It modifies the strings (including serialized ones) in my dumped database. For instance:

        client1.dev —-> client1domain.com
        /var/www/client1_dev —-> /nas/wp/www/sites/client1

        Once that was done, I imported the modified .sql file into WPEngine and overwrote the wp-content directory with my own and the site worked like a charm.

  22. Hi,
    I am probably doing something wrong but after moving the databse, searching and replacing url in it and copying the wp-content folder i still see the same old “just another wordpress site” instead of a copy of my actual site at the new server.
    Any suggestions on what i’ve missed?

    1. Look in wp-config.php and make sure all the database info is correct (host, username, password, and table prefix). It sounds like that site is looking at a different database that has a blank WordPress install in it.

  23. Hi,

    I just migrated a ‘WordPress-WooCommerce’ site from dev server to client’s server. Though all the posts etc transferred correctly, none of the product images show up – the media manager doesn’t seem to recognize the earlier files in the ‘uploads’ directory. As a test, a uploaded a image for a product and it shows up on the page

    I used ‘interconnectit/Search-Replace-DB’ to replace old URLs with new one. Will Steps 9 & 10 of your process resolve this issue or, do you have any other tip.


    1. Did you follow all of these steps for your migration? It sounds like you didn’t. Instead of just doing Steps 9 & 10, I recommend you start over from Step 1.

  24. Hi,

    Would you recommend disabling my plugins when I attempt to migrate my site. I previously tried migrating and got errors caused by wptotal cache plugin.


    1. I don’t use caching plugins when I’m doing development since you have to continually rebuild the cache. But you shouldn’t have any issues migrating with the plugins active – just rebuild the cache once you get over there. Make sure you’re copying over the entire wp-content directory. W3TC adds some files to the top level of /wp-content, and if those don’t make it over then you’ll have errors.

  25. Hi Bill,
    What was your opinion on WP Engine and Pantheon use of blog valt in order to migrate websites?

    Specifically what is your opinion of container-based web hosting? there is a little bit more to go through but it seems like it is a wiser choice.

    I would love to hear anything you have to say on the topic.

  26. I wonder if you have ANY advice for me at all. I changed the domain on my site three days ago and now it is completely broken — nothing works. As you can see, there’s no formatting whatsoever, I can’t get images to load, and plugins don’t even work properly. I have done everything I can think of from running the search/replace tool on the database to tweaking permissions of the directories and image files. I’ve even deleted and reinstalled my theme files (Genesis framework News Pro child theme). Nothing is fixing this. The host says it’s not their problem because they don’t handle data migration issues. :-/

    1. It looks like your site is referencing all files in a /wordpress directory but the files aren’t there. For instance, your stylesheet is: http://www.theaterbyte.com/wordpress/wp-content/themes/news-pro/style.css but that link 404’s.

      Two possible issues:
      1) The URLs are wrong. You should update them to the actual location (although since I can’t find the actual URL I think it’s #2)
      2) The file permissions are incorrect on your server, preventing the files from being accessed. Directories should be 755 and files should be 644. Also make sure the owner is correct. Your host should be able to help with this.

      If your host isn’t helpful, I recommend you move to a higher quality host like WPEngine. You could even use Godaddy’s Pro WP Managed Hosting which is low-cost and provides better service than your host has so far.

Leave a comment