How to Fix WordPress Images Not Loading or Showing as Broken
Broken image icons, blank boxes or images that never appear. Read the status code, then fix paths, permissions, hotlink rules, WebP, lazy load or srcset.
Gray squares in the Media Library, soft or pixelated images, crops that do not fit, or a grid that takes ages to load. Find which image size is wrong and regenerate safely.
Your images are not broken outright, they are just wrong. The Media Library shows gray placeholders or the full file where a thumbnail should be. Product or post grids look soft and pixelated, especially on high resolution screens. Featured images are cropped in odd places, or every image in a gallery is a slightly different shape. Or the Media Library grid takes many seconds to load, and the dashboard slows to a crawl whenever you add an image to a post.
All of this traces back to how WordPress turns one upload into many files. Every upload is copied into a set of registered sizes, and themes, page builders and the browser pick which copy to show. When a size was never created, was created for an old theme, or was squeezed too hard by an optimizer, you see it on the page. When there are tens of thousands of uploads with large metadata, you feel it in the admin. This guide works through each case. If images are not loading at all (broken icons, 404s), FG-48 covers that; for images that make the page slow to load for visitors, see FG-11.
When you upload an image, WordPress saves the file, then asks the image editor (Imagick or GD) to make a smaller copy for each registered size. Each copy gets a suffix with its dimensions, such as photo-300x200.jpg. The list of sizes and their file names is stored in the attachment’s _wp_attachment_metadata field.
| Size name | Default dimensions | Notes |
|---|---|---|
thumbnail |
150 x 150, cropped | Settings, Media |
medium |
Up to 300 x 300 | Settings, Media |
medium_large |
768 wide, any height | Not shown in Settings; used mainly in srcset |
large |
Up to 1024 x 1024 | Settings, Media |
1536x1536, 2048x2048 |
Up to those dimensions | Added in WordPress 5.3 for high resolution screens |
| Theme and plugin sizes | Whatever they register | Created with add_image_size(), often cropped to a fixed shape |
Three rules explain most surprises:
photo-scaled.jpg, which becomes the “full” size. The untouched original is kept on disk and recorded as original_image in the metadata. The threshold can be changed with the big_image_size_threshold filter.On the front end, WordPress adds a srcset attribute listing every stored size with the same aspect ratio as the one requested (up to 2048 pixels wide by default), plus a sizes attribute describing how wide the image is displayed. The browser then picks the smallest file that is sharp enough for the screen. Cropped sizes with a different shape are left out of srcset, which matters in Step 3.
JPEG copies are saved at quality 82 by default and WebP copies at 86 in current versions, adjustable with the wp_editor_set_quality filter. The original upload is not recompressed by WordPress itself.
You need an administrator login. For regeneration and checks you need SSH with WP-CLI; without it, a regeneration plugin such as Regenerate Thumbnails does the same job in the browser, more slowly. Back up wp-content/uploads and the database first: regeneration rewrites metadata and, by default, deletes size files that are no longer registered.
How to run commands in this guide:
wp-config.php). Your host may name the tool wp or wp-cli.screen or tmux on the server if your SSH connection may drop.On the problem page, right-click the image and choose Inspect. With the img element selected, run this in the Console tab:
[$0.currentSrc, $0.naturalWidth + 'x' + $0.naturalHeight, $0.clientWidth + 'x' + $0.clientHeight, window.devicePixelRatio]
This runs in the browser console. $0 means “the element selected in the Elements panel”, so there are no placeholders.
currentSrc is the file the browser actually chose from srcset.naturalWidth and naturalHeight are the file’s real pixel dimensions.clientWidth and clientHeight are the size it is displayed at in CSS pixels.devicePixelRatio is 1 on a standard screen and 2 or 3 on high resolution phones and laptops.Good output: the natural width is at least the displayed width multiplied by the pixel ratio, for example a 768 pixel file displayed 360 wide on a ratio 2 screen. Bad output: a 300 pixel file displayed 600 wide on a ratio 2 screen, which needs 1200 pixels and will look blurry. The file name suffix tells you which size was used, and that points to the step that applies.
wp media image-size
wp post meta get ATTACHMENT_ID _wp_attachment_metadata --format=json
Run these over SSH in the site folder.
wp media image-size lists every registered size with width, height and crop, including theme and plugin sizes.ATTACHMENT_ID is the image’s ID. In the Media Library, open the image; the URL ends with item=ATTACHMENT_ID (grid view) or post=ATTACHMENT_ID (edit screen).--format=json prints the stored metadata, including a sizes object with each generated size and its file name.Good output shows a sizes entry for each size smaller than the original. An empty sizes object, or missing names that should be there, confirms the sizes were never created. If the metadata lists files that are not on disk, the files were deleted or offloaded (Step 6).
intermediate_image_sizes_advanced filter, often in a performance plugin’s “disable image sizes” setting.wp media regenerate --only-missing --yes
Run this over SSH in the site folder.
--only-missing creates only sizes that do not yet exist and leaves existing files alone. It is the safest option and much faster on large libraries.--yes skips the “are you sure” prompt, which only appears when you do not list IDs.Good output ends with “Success: Regenerated COUNT of COUNT images.”, where COUNT is the number processed. Lines saying an image could not be processed name the attachment; test it alone with wp media regenerate ATTACHMENT_ID and check the PHP error log for memory errors at that moment.
Blurry images almost always mean a small file displayed large. Step 1 tells you which. The usual reasons:
the_post_thumbnail( 'medium' ), or a page builder image element set to “Medium”, requests a 300 pixel file. If the column is 600 pixels wide, the browser stretches it. Change the element’s image size setting to Large or Full, or, in theme code, request a larger size.sizes says (max-width: 300px) 100vw, 300px but the image is displayed 900 wide, the browser picks a small file. Themes and builders set this; WordPress 6.7 and later add sizes="auto" to lazy-loaded images so the browser can use the real layout width.width: 100% on an image inside a wide container, or object-fit: cover on a tall box, scale small files up. Inspect the element and check the computed width.After registering a new size or changing one, regenerate only that size:
wp media regenerate --image_size=SIZE_NAME --yes
Run this over SSH in the site folder.
SIZE_NAME is a name from wp media image-size, such as large or a theme size like THEME_CARD_SIZE. Repeat the flag to regenerate several sizes at once.--image_size, only the named sizes are rebuilt; all other size files are left as they are.Good output shows “Regenerated “SIZE_NAME” thumbnail” lines, and “No “SIZE_NAME” thumbnail regeneration needed” for images that already had a correct file.
If you changed Settings, Media or switched themes and want every image rebuilt to the new sizes, run a full regeneration. Read the warning first.
Warning: a full regeneration deletes every existing size file that is not part of the current size list, for every image in the library, unless you add --skip-delete. Posts that link directly to an old size file (common in older posts and page builder layouts) will then show broken images.
wp post list --post_type=attachment --post_mime_type=image --format=count
wp media regenerate --skip-delete --yes
Run these over SSH in the site folder.
--skip-delete keeps old size files on disk. Use it unless you are sure nothing links to them. It costs disk space but cannot break existing pages.--delete-unknown (only in recent WP-CLI releases; check wp cli version if it is not recognized) does the opposite job: it only removes files for sizes that are no longer registered, without regenerating. Use it later, once you have checked that no content references them.To check whether content links to specific sizes, search post content for size suffixes:
wp db query "SELECT ID, post_title FROM PREFIX_posts WHERE post_content REGEXP '-[0-9]+x[0-9]+[.](jpe?g|png|webp)' AND post_status = 'publish' LIMIT 20;"
Run this over SSH in the site folder. PREFIX_ is your table prefix from wp db prefix (often wp_). The pattern matches file names with a size suffix like -600x400.jpg. Any results mean pages that depend on size files, so keep --skip-delete. Page builders that store layouts in post meta need a search of PREFIX_postmeta as well.
If images look blocky, banded or smeared (especially skies, gradients and skin tones), an optimizer may have compressed them too hard. Most optimization plugins have a “lossy” or “aggressive” level and some recompress the original upload as well as the sizes.
wp-content/uploads from a host backup taken before the optimizer ran, or re-upload the originals from your own files.wp media regenerate --yes (with --skip-delete if Step 4 applies) once the originals are back, then re-optimize at a gentler level.Before bulk optimizing again, test a handful of images at each compression level and look at them at 100 percent zoom on a high resolution screen.
WordPress accepts WebP uploads (since 5.8) and AVIF uploads (since 6.5) if the server’s image editor supports them; check the supported formats rows in Site Health, Media Handling. Since 6.7, HEIC uploads are converted to JPEG for the sizes by default, through the image_editor_output_format filter.
Core does not convert JPEG uploads to WebP by default. You can do it with that same filter, with the official Modern Image Formats plugin (from the WordPress Performance Team), or with an optimization plugin or CDN that serves WebP or AVIF on the fly. Problems to watch for:
.jpg but a .webp is served, needs the cache and CDN to vary on the browser’s Accept header. If not, a browser that cannot show WebP may be served one from the cache.wp media regenerate; rerun the plugin’s own bulk process after regenerating.The grid view loads attachments through an AJAX request to admin-ajax.php with the action query-attachments, and builds the month filter with a query over every attachment. On libraries with tens of thousands of items, large postmeta tables and slow storage, both can take seconds.
wp post list --post_type=attachment --post_status=inherit --format=count
wp db size --tables --size_format=mb
du -sh wp-content/uploads
Run these over SSH in the site folder.
inherit status).wp db size --tables shows each table’s size; --size_format=mb prints megabytes. A postmeta table far larger than posts often comes from attachment metadata and plugin data per image.du -sh prints the total size of the uploads folder in a readable unit.To see the slow part, open developer tools, Network tab, filter for admin-ajax, and load the Media Library. Check the time of the query-attachments request. With Query Monitor installed, open its panel on the Media screen to see the slowest queries and which component ran them. FG-34 covers general database bloat; here is what is specific to media:
media_library_months_with_files filter, which WordPress added for exactly this problem on very large libraries.For very large libraries, many sites move uploads to S3-compatible object storage and serve them from a CDN. An offload plugin copies each upload and its sizes to the bucket and rewrites URLs. This frees disk space and moves image traffic off the server, but it changes how every step above works:
Whatever you choose, keep the number of registered sizes in check. Every size is another file per upload, more work per upload, and more rows to scan. Run wp media image-size and question every theme or plugin size you do not actually use.
Open a ticket if uploads repeatedly fail with the “server cannot process the image” message, if Site Health shows no active image editor or missing WebP or AVIF support you need, if regeneration stops with memory or time limit errors, or if you need wp-content/uploads restored from before an optimizer ran. Include:
To check how your images load for visitors, try our diagnostic tools.
Did this fix it?
Still stuck? Start again from what you can see in the Emergency Room.
Still stuck?
Print a free one-page checklist to keep, or open the Emergency Room if the symptom does not match.
Get the free checklistsKeep reading
Search the field manual
Or jump straight to a symptom
Press / to search from any page, Esc to close