---
title: Missing Images After a WordPress Migration: Database, Filesystem and CDN Checks
description: Fix missing WordPress images after migration by checking attachment records, files, generated sizes, old URLs and CDN delivery in the safest order.
url: https://wpstack.online/2026/09/13/missing-images-after-wordpress-migration
date_modified: 2026-09-14
author: Aditya Bhimrajka
language: en_US
---

**Missing images after a WordPress migration usually come from a mismatch between four layers: the attachment record, attachment metadata, the uploads filesystem and the URL delivered to the browser.** Do not re-upload everything or run a global replacement until you know which layer failed. A structured audit can separate a wrong URL from a missing original file, absent generated sizes, blocked CDN delivery or content that still points to the old site.

## Start with one broken image, not the whole library

Choose a broken image on a public page and record the page URL, the failed image URL, its HTTP status, the attachment ID if known and whether the original image opens in the Media Library. Then inspect the browser’s network panel or page source. This first example tells you which branch of the investigation deserves attention.

| What you observe | Most likely layer | Next check |
| --- | --- | --- |
| Image URL still uses the old domain | Database content, block markup or cached HTML | Search safely for the old hostname |
| Correct domain, but the URL returns 404 | Filesystem path, offload/CDN or missing derivative | Compare URL with attachment metadata and disk |
| Original works, one size fails | Generated sub-size or stale `srcset` | Inspect the metadata `sizes` array |
| Origin works, CDN fails | CDN mapping, sync, cache or permissions | Bypass CDN and compare responses |
| Media Library record exists but no file exists | Incomplete files migration | Recover uploads from the source or backup |
| File exists but Media Library has no record | Incomplete database import or unmanaged file | Confirm whether the file should be registered |

## Understand the four records WordPress is joining

An image is not just a file. WordPress normally stores an attachment as a post, stores its relative upload path in `_wp_attached_file`, and stores dimensions plus generated sizes in `_wp_attachment_metadata`. The physical original and derivatives live under the configured uploads directory. Content, blocks, post meta, widgets, theme options or custom tables may refer to the attachment ID or to a literal URL.

`wp_get_attachment_url()` derives a URL using the uploads configuration and attachment file value, with legacy fallback behavior. That means a correct-looking database row cannot prove the file exists, and a file on disk cannot prove that content or the CDN points to it.

## Migration triage in the safest order

1. **Freeze destructive cleanup.** Keep the source site or a backup available and do not delete “unused” records while references are unsettled.
2. **Confirm site addresses.** Review WordPress Address, Site Address, upload configuration and any reverse-proxy or CDN host rewrite.
3. **Test origin delivery.** Request the failed path directly from the origin where possible. Record status, redirect chain, content type and case-sensitive path.
4. **Compare database and disk.** For the attachment, compare `_wp_attached_file` and metadata `file` with the actual path under uploads.
5. **Check derivatives.** If the original exists, verify the particular thumbnail or responsive size requested by the page.
6. **Search references.** Look for the old hostname and old uploads path in posts, post meta, options, widgets and plugin-owned tables.
7. **Clear caches last.** Purge page, object, server and CDN caches after the underlying source is corrected.

## Use search-replace without corrupting data

Do not export SQL and replace strings in a basic text editor. WordPress values can be serialized, and changing string lengths incorrectly can corrupt them. WP-CLI’s `wp search-replace` understands serialized data and offers `--dry-run`. Start with a database backup and a dry-run report, limit the table scope when possible, and review the changed columns before applying.

```
wp search-replace 'https://old.example' 'https://new.example' --skip-columns=guid --dry-run

```

That command is an example, not a universal prescription. Multisite, domain mapping, CDN URLs and custom tables change the scope. The attachment GUID is not the general-purpose place to perform a blind URL rewrite. Re-run a dry-run after the real change; it should show no unexpected old-domain references.

## When the original works but thumbnails fail

WordPress attachment metadata records each generated filename, width, height and MIME type. A new theme or changed image-size configuration may request sizes that were never generated. First confirm that the original is intact. Then identify which sizes are missing and regenerate only what is needed using a trusted workflow. Avoid deleting all derivatives until you know that offload plugins, custom crops and backups can reconstruct them.

After regeneration, inspect rendered `src`, `srcset` and `sizes` on representative desktop and mobile pages. A successful generation job is not proof that cached markup or CDN objects now deliver the right file.

## Separate origin problems from CDN problems

A CDN can preserve an old hostname, cache a 404, omit newly generated sizes, rewrite paths or deny access while the origin is healthy. Compare the same asset at origin and CDN. Check response status, `Content-Type`, cache headers and case sensitivity. If media is offloaded and removed locally, “missing on the web server” may be expected; the authoritative storage inventory and offload metadata must be included in the audit.

## A worked diagnosis

A migrated article shows its hero image but a gallery contains broken thumbnails. The attachment records use the new domain, and each original file opens. The failed URLs all end in a size registered by the new theme. Metadata lists that size, but the physical derivatives were not copied from staging. Regenerating the missing sub-sizes, syncing them to object storage and purging the affected CDN paths restores the gallery. A global URL replacement would not have fixed this failure and could have changed unrelated values.

## Declare the source of truth before repairing

For every media class, decide whether the authoritative copy is the old server, the new uploads directory, object storage, a digital-asset manager or a backup. Do not regenerate, overwrite or delete until that answer is known. A CDN cache is delivery evidence, not an authoritative archive.

Record source and destination site URLs, uploads base directories, URL bases, database prefixes, offload bucket and region, CDN host, theme image sizes, migration timestamps and checksums. This migration manifest lets the team distinguish an incomplete copy from a bad URL rewrite.

| Layer | Source evidence | Destination evidence |
| --- | --- | --- |
| Attachment record | ID, status, MIME and parent | Record exists with expected identity |
| Attached path | `_wp_attached_file` | Relative path matches storage layout |
| Metadata | Original dimensions and generated sizes | Files and metadata reconcile |
| References | IDs and URL forms in content and fields | Rendered pages use intended host and path |
| Remote delivery | Object key, version and CDN rules | Origin and edge return valid image responses |

## Classify failures by exact requested URL

Capture the failed URL from browser network tools, not from a screenshot. Record redirect chain, status, content type, cache headers, requested dimensions and the page that emitted it. Compare it with the attachment URL and every `srcset` candidate.

A 404 suggests path or object absence; 403 points toward permissions, signed URLs or hotlink policy; 5xx may indicate image transformation or storage failure; 200 with HTML indicates a rewrite or error document. Mixed-content blocking and CSP can prevent a valid image request from being displayed.

## Reconcile attachment IDs and literal URLs separately

Featured images, galleries and custom fields often store attachment IDs. Classic HTML, CSS, builders and imported content may store literal URLs. Replacing a hostname fixes only the second class. Recreating an attachment with a new ID fixes neither unless every ID reference is migrated.

Search post content, post meta, options, widgets, block data, builder JSON, product variations, reusable templates and custom tables. Use serialization-aware tools and the owning plugin’s APIs. Keep before values for rollback and review dry-run counts by table and column.

## Handle filesystem case, permissions and ownership

A migration from a case-insensitive machine can hide filename mismatches that fail on Linux. Compare exact path case, Unicode normalization and URL encoding. Check file readability, directory traversal permissions and web-server ownership. Do not solve a permissions problem by making uploads world-writable.

Confirm MIME and extension agree and that server rules permit modern formats. A valid WebP file returned as HTML or blocked by an old allowlist will appear broken. Test the actual response headers from the destination origin.

## Recover originals before generating derivatives

Regeneration requires a trusted original. If only thumbnails exist, locate the original on the source host, backup or object version history. Do not upscale a small crop and call it restored; quality, composition and metadata differ.

Once originals reconcile, calculate missing registered sub-sizes and generate them through WordPress or the owning media workflow. Preserve custom crops and plugin-specific derivatives unless the owner confirms they can be rebuilt. Process bounded batches and keep a failure list.

## Audit offloaded media and object versions

Review attachment offload metadata, bucket keys, ACL or policy, region, custom domain and whether local files were intentionally removed. Compare source and destination object counts and checksums. A database copy can point at a bucket the destination credentials cannot read.

Use least-privilege credentials and do not expose object keys or signatures in logs. If deletion markers or versioning exist, restore the intended version and confirm the offload plugin recognizes it. Test new uploads as well as migrated objects.

## Repair CDN delivery only after origin integrity

Bypass the CDN and request the origin object. If origin fails, fix storage, metadata or path first. If origin succeeds, inspect CDN origin mapping, path rewrites, cache key, signed access, transformation parameters and stale negative caching.

Purge affected paths rather than the entire site when possible. Then request cold and warm edge responses from representative regions. A cached 200 can conceal a missing origin until expiry, so verify both.

## Test responsive and template-specific delivery

Open home, archive, article, product, gallery, account and email templates on mobile and desktop. Inspect which `srcset` candidate the browser chooses. Test high-density screens and breakpoints around theme thresholds. The fallback `src` can work while a selected derivative fails.

Check Open Graph images, structured data, feeds, image sitemaps, PDFs and transactional emails. These consumers may use absolute URLs outside normal page content. Re-scrape social previews after repair and cache purge.

## Worked case: IDs changed during selective import

A team exports posts and media separately into a site that already contains attachments. Imported media receives new IDs, while a page-builder field still stores old numeric IDs. Literal URLs look correct and files exist, but several hero components render nothing.

The team uses the migration manifest to map source attachment IDs to destination IDs by original path and checksum. It rewrites the builder fields through a supported migration, verifies serialized data and renders every affected template. Creating more attachment records would have increased confusion.

## Worked case: a CDN caches migration 404s

Objects arrive at the origin several minutes after pages go live. The CDN requests them early and caches 404 responses for a day. Origin checks later succeed, but visitors continue to see broken images.

The operator purges only the failed paths, shortens negative caching during the remaining migration and verifies edge and origin responses. Future cutovers upload and reconcile media before switching traffic.

## Create a rollback-safe repair batch

1. Freeze the affected URL or attachment set and record hashes.
2. Back up database records, files, object metadata and current CDN rules.
3. Apply one class of repair on staging: URL, ID, file, metadata or delivery.
4. Reconcile counts and render the affected page set.
5. Deploy a small production batch and purge only relevant caches.
6. Monitor image errors and old-host requests through cache expiry.
7. Record repaired, skipped and failed items; retain rollback artifacts.

## Prevent the next migration failure

Put media inventory, checksums, ID mapping, serialized search-replace, object sync, derivative reconciliation and CDN warm-up into the cutover plan. Run a pre-switch crawl on a hosts-file or preview domain. Block destructive cleanup until the observation window closes.

Test one new upload, one edit, one deletion and one regenerated size on the destination. Migration is incomplete if historical files work but future media lifecycle is broken.

## Build an exception ledger instead of relying on memory

Every unresolved image should become one row in a shared exception ledger. Record the attachment ID, requested URL, page where it appears, failure class, authoritative storage location, owner, proposed repair and verification result. Group rows by root cause rather than assigning each broken image as a separate incident. Fifty failures caused by one missing derivative size should lead to one controlled regeneration job, not fifty manual uploads.

Include a confidence field. A confirmed missing file is different from an asset that could not be checked because a private bucket or custom field was outside the audit. Keep unknowns visible until the responsible system owner supplies evidence. This prevents a clean-looking dashboard from hiding incomplete coverage.

## Validate database repairs at the application layer

After a URL or attachment-ID correction, read the value back through WordPress and render the owning template. A database row can look correct while a builder cache, object cache, translated record or generated stylesheet still emits the old value. Check the editor preview and the public response, then inspect the final image request in the browser.

For serialized values, blocks and builder documents, prefer the owning application or a serialization-aware migration process. Count the records changed and retain the pre-change values. If a repair touches a shared option or template, test every layout that consumes it; a single setting may feed the header, footer, mobile menu and transactional email at once.

## Design a representative migration test set

A complete crawl is useful, but a small deliberate test set finds structural errors faster. Include an old attachment, a recent attachment, a filename with spaces or non-ASCII characters, a WebP image, a transparent image, a featured image, a gallery, a builder background, a product variation, a private download and an offloaded object. Add each registered responsive size and at least one custom crop.

Run the set before cutover, immediately after cutover and after caches have warmed. Compare URL, status, content type, dimensions and file hash where the bytes should be identical. Visual review is still needed for crops and transformations because a technically successful response may contain the wrong image.

## Know when to restore instead of repair

Stop incremental repair when the destination copy is broadly incomplete, attachment paths cannot be mapped reliably, or a bulk replacement changed unrelated serialized data. Restoring a known-good database and uploads snapshot can be safer than layering more guesses onto an uncertain migration. Decide with evidence: estimate affected records, identify the last consistent backup, list changes since that backup and test the restoration path before interrupting production.

If a full rollback is impractical, restore a scoped media set into a quarantine location first. Reconcile hashes and metadata, then promote only confirmed files. Never overwrite a newer user upload merely because it shares a filename with an older source asset.

## Post-migration monitoring that catches delayed failures

Monitor image 404, 403 and 5xx rates by path and referrer; requests to the old hostname; CDN origin errors; transformation failures; and new-upload success. Segment known bots from real visitors so a crawler does not obscure a customer-facing regression. Keep an eye on cache expiry: a warm edge may serve an image successfully even after its origin file has disappeared.

Set a defined observation window that covers page-cache and CDN lifetimes plus at least one scheduled content cycle. During that window, retain the source files and rollback data. Close the migration only after the exception ledger is resolved or explicitly accepted, the test set passes from multiple devices, and new media operations work end to end.

Review analytics and search-console landing pages during that window so the test set includes assets with real visibility. A low-traffic legal page, downloadable document or seasonal campaign may not appear in a short crawl queue yet can still matter operationally. Add business owners to the exception review when technical evidence alone cannot establish whether an image is current.

Finally, document the permanent location of masters and migration evidence. A future redesign should not need to treat the public uploads directory or CDN as the only archive. Clear ownership of originals, derivatives and publishing copies reduces both recovery time and accidental duplication.

## Verify the repair before declaring victory

- Crawl a representative set of pages and collect image 4xx/5xx responses.
- Open home, archive, post, product, gallery and authenticated templates.
- Test desktop and mobile responsive candidates, not only the fallback `src`.
- Confirm the Media Library thumbnail and original attachment URL.
- Run a new reference audit and review unreferenced results manually.
- Check server and CDN logs for requests to the old host or missing paths.
- Keep the migration backup through a defined observation period.

## How Mediachecker helps

[Mediachecker](https://wpstack.online/wpstack-plugin/mediachecker/) can inventory attachment relationships through multiple signals, including parent links, post meta, gallery shortcodes, block data and filename references. It can export scan results and help identify records that need manual investigation. Its recent-upload protection, dry-run option, delete-time recheck and backups are useful after the migration is stable.

**Important limitation:** no media scanner can understand every custom table, dynamically generated URL, remote object-store reference or third-party integration. Mediachecker is evidence for review, not proof that a file is disposable. During migration recovery, use it to find inconsistencies; do not turn an uncertain scan into bulk deletion.

## Related WPStack guides

- [The Complete WordPress Media Library Audit Checklist](https://wpstack.online/2026/09/13/wordpress-media-library-audit-checklist/)
- [WordPress Image SEO Audit: Filenames, Alt Text, Sitemaps and Duplicate URLs](https://wpstack.online/2026/09/13/wordpress-image-seo-audit/)
- [How to Automate WordPress Media Audits Without Automating Unsafe Deletion](https://wpstack.online/2026/09/13/automate-wordpress-media-audits-safely/)

## Frequently asked questions

### Why do images appear in wp-admin but not on the frontend?

The admin may load an original or local URL while the frontend uses a generated size, cached page or CDN URL. Compare the exact two requests rather than treating the Media Library preview as end-to-end proof.

### Should I change attachment GUIDs during a migration?

Usually not as a blanket fix. WordPress and WP-CLI guidance commonly excludes the `guid` column from routine domain replacement. Diagnose the actual stored reference and migration design first.

### Can I regenerate thumbnails if originals are missing?

No. Generated sizes depend on the original or another usable source. Recover the original from the old host, object storage or backup before regeneration.

### Why does clearing the cache fix an image only temporarily?

The underlying page, database value, rewrite or sync process may keep recreating the bad URL or object. Find the source of truth before relying on cache purges.

### When is it safe to resume media cleanup?

After URL replacement, file sync, generated sizes, CDN delivery and representative pages have been verified, and after you retain a tested recovery path. Review cleanup candidates in small batches.

## References

- [WP-CLI: wp search-replace](https://developer.wordpress.org/cli/commands/search-replace/)
- [WordPress: wp_get_attachment_url()](https://developer.wordpress.org/reference/functions/wp_get_attachment_url/)
- [WordPress: wp_get_attachment_metadata()](https://developer.wordpress.org/reference/functions/wp_get_attachment_metadata/)
- [WordPress: wp_get_missing_image_subsizes()](https://developer.wordpress.org/reference/functions/wp_get_missing_image_subsizes/)
