You upload the photo. It lands in the Media Library and looks fine.

Then the live page renders a broken image icon and nothing else.

WordPress images not displaying is a delivery failure, not a missing file. The image sits on the server, and something between it and the browser refuses to hand it over.

This guide covers the 8 causes behind almost every case:

  • Wrong file permissions returning 403
  • Stale URLs after a migration or SSL install
  • Missing thumbnail sizes and failed regeneration
  • Hotlink protection, ModSecurity, and Cloudflare rules
  • Plugin conflicts, lazy loading, and WebP fallbacks
  • Cache layers hiding a fix that already worked

You start with the status code, then apply the fix that matches it.

What Is the WordPress Images Not Displaying Error?

WordPress images not displaying is a delivery failure, not a storage failure. The image file sits in the Media Library and on the server, but the browser receives a 403, a 404, or an empty response instead of image data. The post renders. The picture does not.

This separates it from an upload failure, where the file never reached the server at all. If you are seeing errors during upload rather than after, that is a different problem and belongs with image upload failures in WordPress.

Scope matters here. Featured images, gallery blocks, WooCommerce product photos, and theme header logos each break through a different code path, so “all my images are gone” and “one thumbnail is gone” almost never share a cause.

Context for scale: W3Techs puts WordPress at 41.9% of all websites as of mid-2026, and HTTP Archive’s 2025 Web Almanac shows the median home page loading 19 images against 13 on an inner page.

Have you seen the latest WordPress statistics?

Discover the latest WordPress statistics: market share, security trends, performance data, and revenue insights that shape the web.

Check Them Out →

Front End vs Media Library Failures

Front end only: the Media Library grid looks fine, but visitors see nothing. Points to theme output, lazy loading, cache, or CDN.

Back end only: the grid shows gray boxes while live posts render correctly. Points to missing thumbnail sizes or a broken Media Library state.

Both: the file itself is unreachable. Permissions, path, or firewall.

Broken Image Icon vs Blank Space

The visual signature tells you which layer failed before you open a single tool.

What you seeWhat it meansLayer at fault
Broken image iconRequest sent, non-image responseServer (403/404)
Blank white spaceNo src, or src emptied by a scriptTheme or plugin
Alt text onlyFile missing, markup intactFile path
Gray placeholder boxThumbnail size never generatedWordPress metadata

Anyone still calling it “WordPress images not showing” is describing the same four states.

What Causes Images to Stop Displaying in WordPress?

8 causes account for nearly every case: wrong file permissions, stale URLs after migration, hotlink protection, plugin conflicts, ModSecurity blocks, missing thumbnail sizes, exhausted PHP memory during upload, and cache or CDN layers serving deleted paths. Each produces a distinct HTTP status.

CauseStatus returnedScope
File permissions403 ForbiddenAll images
Wrong URLs after migration404 Not FoundAll images
Hotlink protection403 ForbiddenAll images
Lazy-load or plugin conflict200 OK, nothing renderedFront end only
Missing thumbnail size404 Not FoundSingle size or crop
Memory limit hit on upload200 OK, 0 KB fileSingle image

Trigger events narrow it further. A host migration or SSL install points at URLs, a plugin update points at conflicts, a PHP version bump points at GD Library or Imagick, and a theme switch points at image sizes.

Plugin surface area is real: WordPress sites in the US run an average of 21 plugins each, according to SQ Magazine’s 2025 data. Any one of them can filter image output.

Lazy loading is the quiet offender. HTTP Archive’s 2024 Performance chapter found 6.7% of mobile pages hiding their LCP image source behind a data-src attribute, dropping to 5.9% in the 2025 edition. When the swap-back script dies, the image never appears.

The 403 response in WordPress is the single most misread status here, because three unrelated causes all produce it.

How to Identify Which Cause Is Breaking Your Images

Open Chrome DevTools, switch to the Network tab, filter by Img, and reload. The status code returned for the failing file names the cause. Then confirm the file exists on the server at the path the browser requested. 2 checks, 90 seconds.

Do this before touching permissions, plugins, or the database. Every fix below assumes you already know which status you are dealing with.

HTTP Archive’s 2024 data shows the median desktop page requesting 18 images, so the Network tab list stays short enough to scan by eye.

Reading the Status Code

403 Forbidden: something is refusing access. Permissions, hotlink rules, or ModSecurity.

404 Not Found: the path is wrong or the file was never generated.

200 with an empty body: the file exists and weighs 0 KB.

ERRBLOCKEDBYCLIENT: an ad blocker stripped it, usually over a filename containing “ad”, “banner”, or “sponsor”.

Console errors round it out. Mixed content warnings, CORS rejections, and a generic failed to load resource message each point somewhere different.

Checking the File on the Server

Right click the broken image, open it in a new tab, and compare that URL against the real path under /wp-content/uploads/YYYY/MM/.

Connect over FTP with FileZilla or open cPanel File Manager. Two things matter: does the file exist, and what is its byte size?

A 0 KB file means the upload died mid-write. A missing file with a size suffix in the name (image-300x300.jpg) means the thumbnail was never created.

Server logs and the WordPress error log catch what the browser hides, especially PHP fatals during image processing.

How to Fix Incorrect File Permissions on the Uploads Folder

Set directories to 755 and files to 644 across /wp-content/uploads/, applied recursively. Wrong permission values produce a 403 on every image at once while the Media Library still lists them, which is the clearest signature of a permissions problem.

Over SSH the command is find wp-content/uploads -type d -exec chmod 755 {} ; followed by the same pattern with -type f and 644.

Through cPanel File Manager, right click the uploads folder, choose Change Permissions, and check “recurse into subdirectories” before applying. FileZilla offers the identical option under File Permissions.

Ownership is the trap. After a manual restore, files often belong to root or to the wrong user while Apache runs as www-data. The numbers look correct and access still fails.

FTP restores reset uploaded files to 600 more often than people expect. WPBeginner’s guidance notes some hosts need 744 on directories instead of 755, and SiteGround ships a one click Reset Permissions action in Site Tools for exactly this reason.

Never use 777. It makes every file world-writable and solves nothing that 755 does not already solve. Full detail on correcting these values lives in the guide to fixing WordPress file permissions.

How to Fix Image URLs After a Domain Change or HTTPS Migration

Run a search and replace across the database to swap old absolute URLs for new ones, then update siteurl and home in wpoptions. WordPress stores absolute image URLs inside postcontent and inside serialized theme options, so both need rewriting.

The 2025 Web Almanac Security chapter puts HTTPS at 97.3% of mobile homepages, up from 95.6%. That migration wave is exactly what stranded millions of http:// image references inside post content.

Let’s Encrypt now issues roughly 63.4% of all certificates (SSL Insights, mid-2025), which means most of these SSL installs happened automatically at the host level, without anyone touching the database afterward.

Fixing Serialized Data Safely

Never run a raw SQL find and replace. Serialized arrays store string lengths as integers, so changing a URL’s character count without updating the prefix corrupts the value and the option stops loading.

Use Better Search Replace with a dry run first, or wp search-replace 'http://old.com' 'https://new.com' --all-tables --dry-run through WP-CLI.

Both tools unserialize, replace, and reserialize correctly. phpMyAdmin does not.

Clearing Mixed Content Warnings

An https page requesting an http image gets that request blocked by every modern browser, which reads as a broken image even though the file is fine.

The database replace above fixes the stored references. Really Simple SSL rewrites the remaining ones at output as a fallback.

Hardcoded http paths inside theme templates survive both. Grep the theme folder before assuming you are done, and check the wider issue of scripts loading from unauthenticated sources.

One more thing worth checking: Media Library entries still pointing at a staging subdomain. Those survive migration silently because the staging server keeps answering.

How to Fix Missing Thumbnails and Cropped Image Sizes

Regenerate the image sizes. WordPress creates derivative files at upload time only, so any size registered after an image was uploaded simply does not exist on disk. The full size loads, the crop returns a 404 in WordPress.

Since 5.3, WordPress generates 7 sizes by default from a single upload: thumbnail (150×150 cropped), medium (300×300 max), mediumlarge (768 wide), large (1024×1024 max), 1536×1536, 2048×2048, and the original file.

TriggerWhat breaksFix
Theme switchNew theme image sizes missing on old uploadsRegenerate thumbnails
New add_image_size() callOnly new uploads get the sizeRegenerate thumbnails
GD or Imagick disabledNo image sizes generatedEnable the required extension

Run wp media regenerate through WP-CLI, or install Regenerate Thumbnails for a browser-based run. Back up the uploads folder first.

Check the image library before regenerating. Tools > Site Health > Info > Media reports whether GD Library or ImageMagick is active. Without one of them, WordPress writes the original file and nothing else.

Libraries above 10,000 items time out on shared hosting. Run WP-CLI in batches with --only-missing rather than fighting a browser tab that dies at item 3,000.

Storage grows fast here. A single 4 MB upload on a page builder site generates 8 to 12 derivative files, so a regeneration run on a large library needs disk headroom before it needs patience.

How to Fix Images Blocked by Hotlink Protection or Firewall Rules

Whitelist your own domain in every security layer that inspects image requests. Hotlink protection, CDN firewall rules, ModSecurity, and security plugins each return 403 on files that exist and carry correct permissions, which is why permission fixes alone leave these cases unsolved.

The classic version: cPanel hotlink protection configured for example.com while the site now serves www.example.com. The server treats your own pages as an external site stealing bandwidth.

Wordfence and Sucuri add rules that block direct file access under /wp-content/. Wordfence alone sits on more than 4.2 million websites (SQ Magazine, 2025), so this layer is present on a large share of installs.

Cloudflare and CDN Rules

Cloudflare proxies 23.4% of all websites and 83.5% of sites running any known reverse proxy, per W3Techs’ June 2026 survey. Odds are good it sits in your request path.

Scrape Shield > Hotlink Protection blocks image requests whose referrer does not match. Turn it off, test, then re-enable with the correct referrer list.

Bot Fight Mode throws false positives at image requests from headless browsers and preview tools.

Edge rules break things too. Cloudflare’s December 5, 2025 outage came from a WAF rule that produced widespread 5xx responses across LinkedIn, Zoom, and Discord.

ModSecurity Rejections

ModSecurity inspects requests at the Apache level and rejects patterns it reads as attacks. Filenames containing SQL keywords, long query strings, or double extensions trigger it.

The tell: a 403 that appears in the server error log with a rule ID attached, while WordPress logs nothing at all.

Ask your host to disable the specific rule ID rather than ModSecurity as a whole. Whitelisting one rule keeps the rest of the ruleset doing its job.

How to Fix Plugin and Theme Conflicts That Break Image Rendering

Deactivate every plugin, switch to Twenty Twenty-Four, and confirm the images return. This is the fix path when the image file returns 200 with real bytes and still shows nothing on screen. The delivery worked. The markup did not.

Patchstack’s State of WordPress Security 2025 found 96% of vulnerabilities came from plugins rather than core, which says plenty about where the fragile code lives.

Lazy loading is the usual suspect. Scripts move the real path into data-src and swap it back on scroll. When the swap script dies (often because a JS error killed everything after it), the browser is left holding an empty src.

Check the console for a jQuery is not defined error first. One broken dependency stops the whole lazy load chain.

WebP conversion is the second suspect. Smush, ShortPixel, EWWW, and Imagify all rewrite output to serve WebP. WebP sits near 97% browser support and AVIF around 94% per caniuse, so the missing 3% shows up as blank images on old iOS builds and locked-down enterprise browsers when the fallback is misconfigured.

Caching plugins add a third path: cached HTML pointing at filenames that were renamed or deleted after the cache was written.

Run the isolation with the Health Check & Troubleshooting plugin instead of the Plugins screen. Troubleshooting Mode disables everything for your session only, so visitors never see the site with plugins off.

If the images come back under a default theme, the problem lives in the theme’s image output rather than in a plugin. That is a different repair, covered under WordPress theme errors.

One more culprit nobody expects: ad blockers. uBlock Origin strips images whose filenames contain “ad”, “banner”, or “sponsor”, and the site owner never sees it because they whitelisted their own domain years ago.

How to Fix Server Rules and .htaccess Errors Blocking Image Files

Restore the default WordPress rewrite block in .htaccess, then add MIME type declarations for any format the server does not recognize. Broken rewrite rules and undeclared MIME types both stop image files from being served correctly, even when permissions and paths are perfect.

Which file you edit depends on the stack. W3Techs put Nginx at 33.3% of known web servers in early 2026, Apache at 24.4%, and LiteSpeed near 14.8%.

ServerConfig fileWhat breaks images
Apache.htaccessDuplicated rewrite blocks
NginxServer blockMissing try_files rules for uploads
LiteSpeed.htaccess plus cache rulesCache rules intercepting requests

Plugins write to .htaccess without asking. Security, caching, and redirect plugins all append blocks. Two of them fighting over the same directives produces a 500 internal server error or a silent 403 on static files.

Delete everything between the WordPress markers and let the CMS rewrite them. Settings > Permalinks > Save regenerates the block, which is the same trick that solves permalinks not working.

MIME types matter for newer formats. WordPress added WebP uploads in 5.8 (July 2021) and AVIF in 6.5 (February 2024), but the server still needs AddType image/webp .webp to serve them as images rather than downloads.

SVG files are blocked by default for security reasons, so an SVG logo returning nothing usually means the format was never allowed, not that the file is missing.

How to Fix Uploads That Produce Empty or Corrupted Image Files

Raise the PHP limits and re-upload. A 0 KB file in the uploads folder means the write started and died before finishing, almost always because PHP ran out of memory, execution time, or allowed file size mid-process. The Media Library entry exists. The image data does not.

Test with one small image first. If a 40 KB JPG uploads and displays while a 4 MB one produces an empty file, the limits are confirmed as the cause and you can skip everything else.

PHP Limit Values That Matter

4 directives control whether an upload finishes: memorylimit, uploadmaxfilesize, postmaxsize, and maxexecutiontime.

DirectiveWorkable valueSymptom when too low
memory_limit256MFatal error during image resize
upload_max_filesize64MFile rejected outright
post_max_size64MTruncated upload or 0 KB file

Where you set them depends on the host. Editing php.ini works on VPS setups, while shared hosts usually override it from a control panel.

Adding define('WPMEMORYLIMIT', '256M'); to wp-config.php raises the WordPress ceiling only. It never exceeds what the server allows, which is why the memory exhausted error survives that edit so often.

Nginx enforces its own ceiling through clientmaxbodysize, and hitting it returns a 413 request entity too large before PHP is even involved.

Wrong Upload Path Settings

WordPress writes to whatever uploadpath in wpoptions says, and that value survives migrations pointing at a directory the new server does not have.

Check it directly: wp option get uploadpath. An empty value is correct for a standard install, since WordPress then defaults to wp-content/uploads.

The UPLOADS constant in wp-config.php overrides the database value silently. A path pointing nowhere produces a failed to open stream entry in the error log.

Disk quota deserves a look too. Shared hosting cuts writes off at the limit, and the result is a folder full of 0 KB files rather than an error message.

How Cache Layers Hide Images That Already Work

Clear caches from the inside out: plugin cache, object cache, server cache, CDN, then browser. A correct fix stays invisible while any layer above it keeps serving the old response, which is why so many image repairs look like failures for the first ten minutes.

SQ Magazine’s 2025 data shows 82.4% of WordPress sites run at least one caching plugin, and LiteSpeed Cache alone passed 6 million active installs. Most sites have at least three layers stacked.

OrderLayerHow to clear
1Plugin cacheWP Rocket or LiteSpeed: Purge All
2Object cacheFlush Redis or Memcached
3Server cachePurge Varnish or LiteSpeed cache
4CDNCloudflare: Purge Everything

Hard refresh does not touch a page cache. Ctrl+Shift+R only asks your own browser to skip its copy. The server keeps sending the same cached HTML with the same broken image path.

Cloudflare offers single-file purge alongside Purge Everything. Single file is faster for one replaced image, and Purge Everything is the right call after a migration.

Test in an incognito window on mobile data. That bypasses local cache, local DNS, and any host entry you forgot you added while debugging.

Stale CDN copies of deleted paths are the sneaky version. The origin returns 404, the edge still holds a cached 404, and the image stays broken for hours after the file is back where it belongs.

How to Prevent WordPress Image Display Errors

Treat search-replace as a migration step rather than a repair, test updates on staging, and keep backups that preserve file permissions. The 3 events that break images most often (migration, plugin update, PHP version change) are all predictable and all testable in advance.

WP Engine’s 2025 developer survey reported 72% fewer deployment-related outages among teams using staging environments, with issues resolved roughly three times faster when they did happen.

Migration routine: run WP-CLI search-replace as part of the move, not after someone reports broken images. Update siteurl and home in the same pass.

Update routine: clone to staging, update there, load a media-heavy page, then push. WP Staging and host-level one-click staging both handle this in minutes.

Backup routine: UpdraftPlus sits on more than 3 million sites and restores files, though host-level snapshots preserve ownership and permission values more reliably. Permissions lost in a restore are a common cause of the 403 wave.

Monitoring closes the loop. Watch for 404s under /wp-content/uploads/ in Google Search Console and in raw server logs, since that path shows the problem before a visitor emails about it. The same log habit catches broken links in WordPress long before they cost you traffic.

Upload discipline costs nothing:

  • Compress images before upload using a tool like Adobe Express rather than after
  • Lowercase filenames only
  • Hyphens instead of spaces, no %, &, or #
  • Longest side around 2048px for full-width use

PHP version changes deserve their own check. WordPress.org’s 2026 statistics show PHP 8.2 as the largest branch at 25.8% with PHP 7.4 still on 19.3% of sites, so upgrades are still happening in bulk and GD or Imagick availability shifts with them.

Run Tools > Site Health after every PHP change and after every major release. WordPress 7.0 “Armstrong” landed on May 20, 2026, and version jumps that size are exactly when image libraries and plugin update errors surface together.

FAQ on WordPress Images Not Displaying

Why did my images disappear right after I migrated the site?

Absolute URLs stored in postcontent still point at the old domain. Run a WP-CLI search-replace or Better Search Replace across all tables, then update siteurl and home in wpoptions.

Why do images show in the Media Library but not on the live page?

The file is fine, so the failure sits in output. Lazy loading scripts, cached HTML, or a CDN serving an old path are the usual causes. Deactivate plugins to confirm.

What permissions should the uploads folder have?

755 for directories, 644 for files, applied recursively across /wp-content/uploads/. Some hosts prefer 744 on directories. Never set 777, since it opens the folder to everyone and fixes nothing.

Why are featured images missing while full-size images load?

The cropped size was never generated. WordPress creates derivative files at upload time only, so a theme registering new sizes later leaves older uploads without them. Regenerate thumbnails.

How do I confirm a plugin is breaking my images?

Use Health Check & Troubleshooting rather than the Plugins screen. Troubleshooting Mode disables plugins for your session alone, so you test safely while visitors keep seeing the normal site.

Why does an image return 403 when the file clearly exists?

Three layers produce that status: wrong permissions, hotlink protection, or a ModSecurity rule. Check the server error log for a rule ID. A rule ID rules out permissions immediately.

Do I have to regenerate thumbnails after switching themes?

Yes, if the new theme registers sizes through addimagesize(). Run wp media regenerate --only-missing through WP-CLI on large libraries, since browser-based runs time out past a few thousand items.

Why did images break after installing an SSL certificate?

Mixed content. An https page requesting an http image gets that request blocked by the browser. Replace the stored URLs in the database, then use Really Simple SSL as a fallback.

What causes a 0 KB image file in the uploads folder?

The write died mid-process. Raise memorylimit, uploadmaxfilesize, and postmaxsize, then check disk quota. A generic HTTP error during upload points at the same limits.

I applied the fix and images are still broken. What now?

Cache. Clear the plugin cache, object cache, server cache, and CDN in that order, then test in incognito on mobile data. A hard refresh alone never touches a page cache.

Conclusion

WordPress images not displaying almost never means the file is gone. It means one layer between the uploads directory and the browser stopped cooperating.

The diagnostic order stays the same every time. Read the status code in DevTools, confirm the file on the server, then apply the matching fix.

403 points at permissions, hotlink protection, or ModSecurity. 404 points at stored URLs or missing thumbnail sizes. A 200 with nothing on screen points at plugins and cache.

Fix the cause, then clear every cache layer before judging the result.

One habit prevents most repeats: run search-replace during migrations, test updates on staging, and check Site Health after each PHP version change.

Broken images stop being a surprise.