· Updated

WordPress Links Not Working After Migration: How to Fix

WordPress links not working after a migration is usually stale permalinks or an old domain. Repair the URLs, add 301s, then check the site for broken links.

Quick fix: start with the symptom you have

If all internal WordPress links started returning 404s after a migration, go to Settings → Permalinks and click Save Changes. That flushes WordPress’s rewrite rules and is the fastest fix for the common “homepage works but every post or page 404s” problem. Clear any site or host cache afterwards, then test an old post in an incognito window.

If that does not fix it, use this quick diagnosis before changing anything else:

What you see Most likely cause Fix first
Homepage works, but posts and pages 404 Permalinks or server rewrite rules were not rebuilt Save Permalinks; then check .htaccess or nginx rewrite rules
Links send visitors to the old domain home, siteurl, or hardcoded URLs still use the old domain Update WordPress URLs and run a serialization-safe search-and-replace
Images are broken but pages load Upload paths or old media URLs did not move cleanly Verify wp-content/uploads, then replace old media URLs
Only old bookmarks and backlinks 404 Old URL structure changed Add permanent 301 redirects from each old path or pattern
Pages work but assets show security warnings Old http:// URLs remain after moving to HTTPS Replace insecure URLs and clear caches

Just migrated a WordPress site? Run it through the free website checker to scan its internal links, SSL, and DNS health before you hand it back to the client. No signup required.

Start here: what’s actually broken

You moved a WordPress site — new host, new domain, or you changed the permalink structure — and now links are 404ing. Before you touch anything, figure out which kind of broken you’re dealing with, because the fix is different for each:

  • Internal links 404ing (blog posts linking to other pages on the same site): almost always a permalink structure change or a domain change with unmigrated hardcoded URLs.
  • Images and media not loading: usually a path mismatch — the wp-content/uploads structure didn’t move cleanly, or URLs are still pointing at the old domain.
  • External links to your site are dead (backlinks, bookmarks, search results): the URL structure changed and there’s no redirect mapping old paths to new ones.
  • Mixed content warnings / broken assets over HTTPS: leftover http:// references in content or settings after moving to SSL.

Each of these has a specific cause and a specific fix below. Skip to the section that matches what you’re seeing, but read the “why” section first if you have a few minutes — it’ll save you from fixing the same problem twice.

WordPress builds URLs from a permalink setting (Settings → Permalinks), and it’s easy to end up with a different structure after a migration — especially if a new host or new theme setup wizard reset it, or if you deliberately changed from /?p=123 to /%postname%/ or restructured categories into the URL. Every internal link that was hardcoded to the old pattern (as opposed to generated dynamically by WordPress functions like the_permalink()) breaks immediately, and so does every external bookmark or backlink pointing at the old paths.

Domain changes

Moving from a staging subdomain to a live domain, or from an old domain to a new one, is the single biggest cause of migration link rot. WordPress stores the site URL in two places — siteurl and home in the wp_options table — but that’s not the whole story. Content authored in the classic editor or Gutenberg often contains hardcoded absolute URLs: a link typed as https://oldsite.com/services instead of a relative /services. Changing the options table doesn’t touch those; they’re baked into wp_posts.post_content as literal text, and they’ll keep pointing at the old domain until someone does a search-and-replace across the database.

Media and upload path mismatches

The wp-content/uploads directory is organized by year and month (/uploads/2024/03/photo.jpg), and image URLs in your content reference that exact path — often as an absolute URL, not a relative one. If the migration didn’t preserve the folder structure exactly, or if you moved to a new host with a different uploads path (some managed hosts remap this), every image reference embedded in old posts breaks even though the files themselves may have transferred fine.

Mixed content after adding HTTPS

If the migration included moving to HTTPS (common when switching hosts, since many now provision SSL automatically), any content still referencing http:// URLs for images, scripts, or embeds will either 404, get blocked by the browser as mixed content, or silently downgrade security warnings in the console. This is separate from broken links technically, but it shows up in the same symptom bucket: things not loading that should.

Guessing which pages are affected wastes hours. You want a full inventory before you start fixing anything, because search-and-replace and redirects both work best when you know the complete scope up front.

Manual spot-checking (fine for tiny sites, unreliable at scale)

Clicking through your own nav and a handful of blog posts will catch the obvious stuff, but it won’t catch orphaned older posts, image references buried in old content, or backlinks from other sites — which are exactly the links most likely to be pointing at a URL structure that no longer exists. Treat manual checking as a sanity check, not your primary method.

Crawlers

A site crawler (Screaming Frog, Sitebulb, or similar) will walk every internal link and report status codes, which is the right tool if you want a full technical audit including redirect chains, orphaned pages, and image link status. The tradeoff is setup time and a learning curve if you haven’t used one before, and most have limits on the free tier that matter for larger sites.

If you want something lighter — no software install, just a URL and a few minutes — the free checker at SitesRadar will crawl a site’s links, SSL, and DNS health and flag what’s broken, which is a reasonable first pass to confirm scope before you decide whether a full crawler audit is warranted. The same sweep is available as a one-box website checker if you just want to paste the migrated URL and see what comes back.

Google Search Console

Search Console’s Coverage report (under Indexing → Pages) will show you 404s that Google has actually encountered while crawling your site, which is valuable because it reflects real-world traffic and backlink patterns you might not think to check manually. It’s slower to update than a live crawl — Google needs to recrawl to notice a fix — but it’s the best signal for which broken URLs matter most in terms of search traffic and existing backlinks, so prioritize fixes here alongside whatever a crawler turns up.

Server logs (if you have access)

If your host gives you access to raw access logs, grep for 404 and look at the referrer field — it’ll tell you exactly which broken links are actually being clicked, which is useful for triaging when you have limited time and a long list of 404s to work through.

How to fix it

Once you know the scope, fix in this order: database-level content fixes first, then redirects for anything you can’t fully clean up, then manual link updates for the stragglers.

Search-and-replace URLs in the database

If the root cause is hardcoded absolute URLs — old domain, old permalink structure baked into post content — a database search-and-replace is the direct fix. Don’t do a raw SQL UPDATE with REPLACE() on wp_posts directly; WordPress serializes some data (widget settings, some plugin options) as PHP serialized arrays, and a naive string replace corrupts the length prefixes in that format and breaks the site. Use a tool that’s serialization-aware.

WP-CLI’s search-replace command handles this correctly:

# Dry run first — always
wp search-replace 'https://oldsite.com' 'https://newsite.com' --dry-run

# Then actually run it
wp search-replace 'https://oldsite.com' 'https://newsite.com' --all-tables

# If you also changed permalink structure, e.g. removing a category prefix
wp search-replace '/category-name/2024/' '/2024/' --dry-run

--all-tables matters because URLs can be embedded in options, postmeta, and some plugin tables, not just wp_posts. If you don’t have shell access to run WP-CLI, most managed hosts and plugins like Better Search Replace do the same job through a UI, with the same serialization-safety.

Back up the database before running this against production, even after a clean dry run — a dry run tells you what would change, not that every change is safe for every edge case in your specific content.

Set up 301 redirects for anything you can’t rewrite

Search-and-replace fixes your own site’s internal links, but it does nothing for external backlinks and bookmarks still pointing at the old URLs — those need a redirect. This also covers cases where you deliberately changed the permalink structure and want old URLs to keep working rather than being fully replaced everywhere.

Using the Redirection plugin (WordPress admin), you can map old-to-new patterns including wildcards, which is the easier path if you’re not comfortable editing server config directly, and it gives you a log of which redirects are actually being hit — useful for confirming you caught the traffic that matters.

If you’d rather handle it at the server level, an .htaccess example on Apache:

RewriteEngine On
RewriteRule ^old-category/(.*)$ /new-category/$1 [R=301,L]
Redirect 301 /old-page/ https://newsite.com/new-page/

Or the nginx equivalent:

rewrite ^/old-category/(.*)$ /new-category/$1 permanent;
location = /old-page/ {
    return 301 https://newsite.com/new-page/;
}

Use 301 (permanent), not 302, so search engines transfer ranking signal to the new URL rather than treating it as a temporary detour — this matters for preserving whatever SEO equity the old URLs had accumulated.

After search-and-replace and redirects, there’ll usually be a handful of links that need manual attention — links inside navigation menus, widgets, or page builder content that wasn’t touched by the database replace because it’s stored in a format the tool didn’t parse, or links that point to pages that were genuinely restructured (not just moved) and need a different destination, not just a domain swap. Go through your crawler’s report or Search Console list and update these by hand; there usually aren’t many left once the bulk fixes are done.

Preventing this on the next migration (or the next content change)

The underlying fix is to stop authoring hardcoded absolute URLs in content going forward — link internally with relative paths or WordPress’s own linking tools where possible, so a future domain or permalink change doesn’t require another database sweep. That’s a process fix, not something you can retroactively apply to years of existing posts, so the practical safety net is catching breakage early rather than preventing it entirely.

That means recurring monitoring, not a one-time check after this migration. A link check that runs on a schedule — daily or weekly, depending on how often content changes — catches new 404s from future plugin updates, theme changes, or someone accidentally deleting a page, long before a client or a search engine notices. This overlaps with the same discipline you’d use for general site health monitoring — see the client site down triage checklist for the broader picture of what to watch beyond just links, since a site that’s fully “up” can still be quietly leaking traffic and trust through broken links that nobody’s actively looking for.

For the broader practice of catching those silent homepage, metadata, DNS, and link regressions, see website change monitoring for client sites.

If you’re managing sites for multiple clients, the real cost of broken links isn’t the fix — it’s the lag between when they appear and when someone notices, often a client complaint or a drop in organic traffic weeks later. Whatever tool you use, the goal is closing that gap.

FAQ

Why are my WordPress links not working after a migration?

Nine times out of ten it is one of two things: the permalink structure changed, or the site moved to a new domain and the database still holds the old one. Go to Settings → Permalinks and click Save Changes first — that rebuilds the rewrite rules and fixes the classic “homepage loads, every post 404s” case. If that does not do it, run a search-and-replace across the database for the old domain.

My WordPress internal links are not working, but the pages exist. Why?

The page exists at a URL, but the links pointing to it still use the old path. That is a content problem rather than a rewrite problem, so flushing permalinks will not help. Search the database for the old path and replace it, or add a 301 redirect from each old URL to its new one. Internal links are worth fixing directly rather than redirecting, because a redirect costs a round trip on every click and passes slightly less signal than a direct link.

WordPress 404s after migration — do I need to recreate the pages?

No. Check whether the content is still in the database before rebuilding anything. A 404 after a migration almost always means the URL changed, not that the content vanished. Confirm the post still exists in Posts, then fix the URL or redirect to it. Only recreate content that is genuinely gone.

Can a WordPress update break my links?

It can, though it is less common than a migration. An update that changes a permalink structure, alters a theme’s URL handling, or deactivates a plugin that registered a custom post type will produce the same symptom. If links broke after an update rather than a move, check the permalink settings and re-save them, then look at what the update deactivated.

How do I find every broken link, not just the ones I know about?

Crawling the site is the only reliable way — manual spot-checking misses the links nobody clicks. SitesRadar’s free checker crawls your internal and external links, reports which return 404 or 5xx, and tells you where each one is linked from. Google Search Console’s Pages report is a useful second opinion for URLs it has already crawled.

How do I stop this happening on the next migration?

Stop authoring hardcoded absolute URLs in content — link internally with relative paths so a domain change does not require a database sweep. That is a process fix you cannot apply retroactively, so the practical safety net is catching breakage early with a scheduled link check rather than trying to prevent it entirely.

Monitor one site free forever and SitesRadar will re-check your links on a schedule, alongside uptime, SSL expiry, DNS, and domain expiry — so the next broken link is an email rather than a client complaint.

← More from the SitesRadar blog