Skip to content

Migrate WordPress from Hostinger to cPanel: the manual export and cutover

Hostinger runs its own hPanel instead of cPanel, so this guide shows you how to migrate WordPress from Hostinger to cPanel by hand, mailboxes included. You will finish with the site answering on your own server before any DNS record moves.

This guide is for the admin or developer moving a WordPress site off Hostinger onto a cPanel/WHM server they control. Hostinger runs its own control panel, called hPanel, so no cPanel-format account archive exists for WHM’s Transfer Tool to fetch. The short answer is that you move the files, the database and the mail yourself, along one of three routes. Which route is open to you depends on whether your plan includes SSH, a remote shell on the server. By the end the site answers on your own server, tested against its real hostname, before a single DNS record moves.

What you’ll accomplish

  • A clear decision on which export route your Hostinger plan leaves open.
  • A complete copy of the files and the database on your cPanel account, checked rather than assumed.
  • Every mailbox re-created on cPanel before the MX records move. MX means mail exchanger, the DNS record naming the server that receives a domain’s mail.
  • Hostinger’s platform code removed, including any must-use plugin the panel injected. A must-use plugin is one WordPress loads on every request, with no off switch in the admin.
  • LiteSpeed Cache settings and .htaccess rules reviewed against the web server your cPanel box runs.

Prerequisites

On the Hostinger side you need the login for the account that owns the hosting, not only a WordPress administrator. One fact decides your export route: whether the plan gives you SSH. Hostinger offers it on business and cloud plans, and the cheapest shared plans may not. Confirm by connecting, rather than by reading a feature table.

On the destination you need a cPanel account for the domain, a MySQL database and database user, SSH access, and wp on the box. wp is WP-CLI, the WordPress command-line tool, documented in the WP-CLI command reference.

Match the PHP version before you copy anything. Read it from hPanel’s PHP configuration screen, then set the same version in cPanel’s MultiPHP Manager. A site on PHP 8.2 that lands on an account defaulting to 7.4 fails in ways that look like a corrupt upload. Handling a PHP version jump during migration covers the cases where the versions cannot match.

Write down every mailbox, alias and forwarder on the domain while you are still in hPanel. Hostinger sells mail as a separate product, under the Hostinger Email and Titan names, so mailboxes and their contents do not travel with the files and database. Decide now whether mail follows the site to cPanel or stays put. That one decision causes most of the pain in this kind of move.

Then lower the TTL on the domain’s A, AAAA and MX records to 300, at least 24 hours ahead. TTL means time to live, the number of seconds a resolver may keep a cached answer. Lowering an 86400-second TTL two hours before the flip changes nothing, because the old value is still cached.

How it works

A migration moves three things: the files, the database, and the DNS records that point visitors at them. Around those sits whatever the old host wrapped about the site. On Hostinger that is hPanel plus a LiteSpeed web server, and neither packages your account the way WHM expects. hPanel’s backup tool gives you a ZIP of your files and, separately, an SQL dump. Neither is a cpmove archive, the cPanel-format bundle the Transfer Tool restores, so each piece travels on its own.

Decision diagram showing how SSH availability on a Hostinger plan selects between the hPanel backup route, a migration plugin and an SSH plus WP-CLI export, with the manual work common to all three

The routes differ only in how the bits leave Hostinger. Route A needs nothing but a browser and works on every plan, at the cost of unpacking archives by hand. Route B covers Duplicator, All-in-One WP Migration and similar tools, which run inside PHP. On a large site that export can hit memory_limit and leave an archive that looks finished and is not. Route C is cleanest when the plan has SSH, because a WP-CLI dump plus a tar of wp-content is small and checkable before it moves.

Two Hostinger-shaped things come across with the files on any route. The first is the panel’s own plugin, installed on every new site it builds. The second is the LiteSpeed Cache configuration, which fits a LiteSpeed web server and does nothing useful on an Apache one. Most cPanel servers run EA4, short for EasyApache 4, cPanel’s Apache build. Other own-panel hosts have the same shape, and migrating WordPress from SiteGround to cPanel covers that one.

Step-by-step

Everything before the freeze in step 13 is rehearsal you can repeat. Everything after it is live.

  1. Confirm SSH, then pick your route. Try the connection with the host, port and username hPanel’s SSH section shows:

    ssh -p SSHPORT USER@HOSTNAME 'wp --info'

    A working shell prints the WP-CLI version block, starting with OS: and ending with WP-CLI version:. Take Route C. If the connection is refused, or the plan shows no SSH section, take Route A and use hPanel’s backup tool plus its database export. Take Route B only when Route A is blocked too.

  2. Inventory the site while it is still on Hostinger. With SSH:

    wp core version
    wp core verify-checksums
    wp plugin list --status=active --fields=name,title,version
    ls -1 wp-content/mu-plugins/
    wp db size --tables --size_format=mb
    pwd

    Write down the core version, because you will reinstall exactly that one. verify-checksums prints Success: WordPress installs verify against checksums., and anything it flags is a modified core file. Keep the pwd output: Hostinger home directories look like /home/u123456789/domains/example.com/public_html, and that string sits in your database. Without SSH, read the version under Dashboard then Updates and use phpMyAdmin instead.

  3. Export the database. With SSH:

    wp db export hostinger.sql --add-drop-table

    Expect Success: Exported to 'hostinger.sql'. Without WP-CLI, use hPanel’s database export, or phpMyAdmin’s Export screen with the option that adds DROP TABLE statements. Either way, check the tail:

    tail -3 hostinger.sql

    It must end on a complete statement, not partway through an INSERT. A truncated dump imports without complaint and quietly loses the end of your largest table. For a gzip file, use gunzip -c hostinger.sql.gz | tail -3.

  4. Package the files. From the site root over SSH:

    tar -czf ~/hostinger-files.tar.gz wp-content wp-config.php .htaccess

    Core files are not worth moving, because step 6 downloads a clean copy. tar prints nothing on success, so compare ls -lh ~/hostinger-files.tar.gz against the disk usage hPanel reports. On Route A the backup ZIP replaces this step; on Route B, the plugin’s archive.

  5. Move the archive to the cPanel server. Pull rather than push, running this on the destination as the cPanel account user:

    scp -P SSHPORT USER@HOSTNAME:hostinger.sql USER@HOSTNAME:hostinger-files.tar.gz ~/

    scp prints one progress line per file, each ending at 100%. Run it as the cPanel account user. As root, every file lands owned by root and WordPress cannot write to wp-content. On Route A, upload both files through cPanel’s File Manager.

  6. Rebuild the site on cPanel. Create the database and database user in cPanel’s MySQL Database Wizard first, and note the three values. Then:

    cd ~/public_html
    wp core download --version=WPVERSION --skip-content
    tar -xzf ~/hostinger-files.tar.gz -C ~/public_html
    wp db import ~/hostinger.sql

    Substitute the version from step 2. --skip-content leaves wp-content empty so the tarball fills it. Expect Success: WordPress downloaded. then Success: Imported from 'hostinger.sql'.

  7. Rewrite the database credentials in wp-config.php. The Hostinger values in the file you copied point at a database this server does not have. Replace them with the ones cPanel gave you in step 6:

    wp config set DB_NAME CPUSER_wpdb
    wp config set DB_USER CPUSER_wpuser
    wp config set DB_PASSWORD 'THEPASSWORD'
    wp config set DB_HOST localhost
    wp db check

    Each config set answers Success: Updated the constant ... in the 'wp-config.php' file. wp db check then reports OK for every table, which proves the credentials work and the import landed.

  8. Remove Hostinger’s platform code. List what is there first, since the set differs with how the site was built:

    wp plugin list --fields=name,title,status
    ls -1 wp-content/mu-plugins/

    Anything whose title names Hostinger is panel code, not site code. Remove it by the slug in the name column:

    wp plugin deactivate PLUGINSLUG
    wp plugin delete PLUGINSLUG

    Those return Success: Deactivated 1 of 1 plugins. and Success: Deleted 1 of 1 plugins. Files in wp-content/mu-plugins/ have no admin toggle, so delete them with rm -f. Read each first, because a developer may have put real site code there.

  9. Decide what happens to LiteSpeed Cache. Find out what your destination runs:

    curl -sI --resolve example.com:443:NEWIP https://example.com/ | grep -i '^server:'

    A reply of server: LiteSpeed means the plugin still has a server to talk to, so keep it and clear its settings once. A reply of server: Apache means its cache has nothing behind it, so deactivate it and clean the rules it wrote:

    wp plugin deactivate litespeed-cache
    grep -n "LSCACHE\|LiteSpeed" ~/public_html/.htaccess
    ls -l wp-content/advanced-cache.php wp-content/object-cache.php

    The grep gives line numbers for each block. Delete every block from its # BEGIN marker to its matching # END marker, and nothing outside them. Then delete any advanced-cache.php or object-cache.php drop-in the ls finds, since both call caching services this server does not run.

  10. Create the mailboxes now, before MX moves. Work from the list you made in the prerequisites. Create each address in cPanel’s Email Accounts screen with the same local part, then add the forwarders. Copy the mail across while the old provider still holds it:

    imapsync --host1 OLDIMAPHOST --user1 you@example.com --password1 OLDPASS --host2 localhost --user2 you@example.com --password2 NEWPASS

    Use whatever incoming server your mail provider’s settings page names as --host1. imapsync ends with a transfer summary and a line reading Detected 0 errors. For two or three mailboxes, adding both accounts to a desktop mail client and dragging folders across works too.

  11. Validate on a temporary hostname before DNS moves. The diagram below shows where this sits in the sequence.

    Timeline of the cutover, running from building the cPanel account and mailboxes through copying files and database, validating on a temporary hostname, lowering TTL, moving MX and A records, verifying, and decommissioning the old plan

    Point your own machine at the new server without changing anything public:

    curl -o /dev/null -s -w '%{http_code} %{time_total}s\n' --resolve example.com:443:NEWIP https://example.com/
    curl -sI --resolve example.com:443:NEWIP https://example.com/wp-login.php | head -1

    Both should answer 200. --resolve sends the request to NEWIP while still asking for example.com, so you see what a visitor will see after the flip. To click around in a browser, add the same mapping to your hosts file. Get the certificate issued in this window too, using AutoSSL’s DNS validation, because HTTP validation cannot pass until the domain resolves here. cPanel’s documentation portal covers it.

  12. Fix the stored paths, and the URLs only if the domain changes. Most moves keep the domain, so the URLs in the database are already right and you should leave them alone. The absolute file path from step 2 does change. Dry run first:

    wp search-replace '/home/u123456789/domains/example.com/public_html' '/home/CPUSER/public_html' --all-tables --dry-run --report-changed-only
    wp search-replace '/home/u123456789/domains/example.com/public_html' '/home/CPUSER/public_html' --all-tables --precise

    --all-tables walks every table, including any a plugin created under a different prefix. --precise keeps serialised arrays valid when a replacement changes a string’s length, because WP-CLI unserialises in PHP instead of using raw SQL. Running search-replace across a migration covers a domain change.

  13. Freeze, sync the delta, then move DNS. Put the Hostinger site into maintenance mode so no order, comment or form entry lands after your final export. Re-run steps 3 and 4, import, re-run step 12, then flush:

    wp rewrite flush --hard
    wp cache flush

    Expect Success: Rewrite rules flushed. and Success: The cache was flushed. The --hard form rewrites the WordPress block in .htaccess, not only the copy in the database. That matters because step 9 cut a chunk out of that file. Now change MX first, then A and AAAA.

Validate it works

About an hour after the flip, check from the inside:

wp option get siteurl
wp option get home
wp db check
wp core verify-checksums

Both options must return the final domain, wp db check should report OK on every table, and checksums should verify. Then put your twenty busiest URLs in a file and sweep them:

while read -r u; do code=$(curl -o /dev/null -s -w '%{http_code}' "$u"); echo "$code $u"; done < top-urls.txt

Every line should read 200, or 301 where you redirect on purpose. Then check resolution, certificate and mail routing from outside:

dig +short example.com @1.1.1.1
dig +short MX example.com @1.1.1.1
curl -sI https://example.com/ | head -1

The first must return your cPanel server’s address, the second your mail host, and the third HTTP/2 200 with no certificate warning. Then send a real message to each mailbox and reply from it, and exercise site-sent mail with a password reset and a contact form. Post-migration monitoring in the first 72 hours lists what to watch next.

Troubleshooting

Mail bounces or disappears right after cutover. If the mailboxes were not created before MX moved, mail arrives at a server with nowhere to put it. If MX still points at Titan or another provider, cPanel treats a domain on its own account as a local mail exchanger and swallows the message. Set Remote Mail Exchanger in cPanel’s Email Routing screen.

The hPanel backup ZIP will not restore in WHM. That is expected. It is a plain archive of your files rather than a cpmove account bundle, so the Transfer Tool has no use for it. Unpack it into ~/public_html yourself and import the SQL dump separately, as steps 6 and 7 describe.

Every page except the homepage returns 404. The rewrite rules are gone, usually because the .htaccess edit in step 9 took the WordPress block out with the LiteSpeed blocks. Run wp rewrite flush --hard, confirm the block between # BEGIN WordPress and # END WordPress reappears in ~/public_html/.htaccess, and check that the account allows overrides.

A white screen, or a warning about a missing cache class. A drop-in from the old stack is still in place, usually wp-content/object-cache.php or wp-content/advanced-cache.php. Both load before your plugins and both call services this server does not run. Delete them, then reload.

When this is the wrong approach

If you are leaving because the site felt slow and nobody wants to own performance, know what you are giving up. Hostinger runs LiteSpeed with a server-level page cache, so a theme that felt quick there was measured with much of PHP bypassed. On an unmanaged cPanel account that layer does not exist until you build it.

If the domain’s mail is the business, split the move in two. Migrate the website, leave the mailboxes with Titan or Hostinger Email, and set the domain to Remote Mail Exchanger. That takes the riskiest lane out of the cutover, and mail can follow later.

If the domain is also registered at Hostinger and you plan to move the registration, do not do both in the same week. A registrar transfer has its own multi-day window and its own failure modes. Move the hosting first, prove it, then the registration.

Running WordPress that earns real money deserves an operator — Stack Harbor runs that stack under Enterprise WordPress; book an infrastructure consult.