
What Is Mixed Content?
Mixed content is the situation where a webpage is loaded over HTTPS but includes resources — such as images, JavaScript files, CSS stylesheets, or iframes — that are loaded over HTTP (unencrypted). Despite the main page URL being https://, the browser cannot confirm the full page is secure because some elements are coming from an insecure channel.
The result: even after you install an SSL certificate and your site loads at https://, the padlock icon may not appear, or a warning icon may display in its place. Some users may see a "Not Secure" indicator. This is mixed content at work, not a problem with your SSL certificate itself.
Two Types of Mixed Content
1. Passive Mixed Content (Warning)
Resources loaded over HTTP that cannot directly modify page content, such as images (<img>), video, and audio. Browsers display a warning but still load these resources, since the risk level is lower. However, the padlock will typically show an information or warning icon rather than the secure padlock.
Example: An HTTPS page embedding an image from another domain via http://example.com/photo.jpg
2. Active Mixed Content (Blocked)
Resources that can modify or control the page's DOM — JavaScript (<script>), CSS (<link rel="stylesheet">), iframes, and XMLHttpRequests. Browsers block these entirely because they represent a high security risk. Blocked active mixed content can cause functionality on your page to break silently.
Most common cause: Migrating a website from HTTP to HTTPS without updating all resource URLs in the database or code. Images, scripts, and links continue to point to http:// URLs even after the SSL is installed.
Active vs Passive Mixed Content: What's the Difference
Many people are confused why some pages with mixed content still open normally (just without a padlock) while others break entirely. The answer lies in whether the HTTP resource is passive or active, because browsers treat the two categories completely differently. Understanding this distinction helps you prioritize your fixes correctly and avoid wasting time chasing low-impact issues first.
Passive mixed content is content that only "displays" but cannot control the page — images, video, and audio. Even when loaded over HTTP, browsers allow them to load because the risk is limited. An attacker performing a man-in-the-middle attack could at most swap an image or observe what the user is viewing. The consequence, however, is that the browser downgrades the security status of the entire page: the padlock disappears and a "Not fully secure" warning shows up.
Active mixed content is content that can "control" the page — JavaScript, CSS, iframes, fetch/XMLHttpRequest, and web fonts. If an attacker intercepts and replaces a script loaded over HTTP, they can run arbitrary code on your page, steal cookies, alter content, or redirect users to a fake page. Because of this high risk, modern browsers (Chrome, Firefox, Edge, Safari) block it outright without asking. The result is broken styling, buttons that don't work, or forms that fail to submit.
| Aspect | Passive | Active |
|---|---|---|
| Example resources | img, video, audio | script, CSS link, iframe, fetch |
| Browser behavior | Loads + warning | Blocked outright |
| Impact | Padlock lost | Broken functionality and styling |
| Urgency | Medium | Very high |
In short, active mixed content must always be fixed first because it breaks the site's actual functionality. Passive content should be fixed too so the padlock returns, but it won't take the site down. A good approach is to start with scripts and CSS, then move on to images and media afterward.
Finding Mixed Content with the Browser Console and Why No Padlock
Using Browser DevTools
- Open your webpage in Chrome
- Press F12 or right-click → Inspect to open DevTools
- Click the Console tab
- Look for red or yellow messages starting with "Mixed Content:" such as: "Mixed Content: The page at 'https://...' was loaded over HTTPS, but requested an insecure resource 'http://...'"
- The URL shown in the error message is the resource you need to fix
Using Online Tools
Tools like "Why No Padlock" (whynopadlock.com) or various SSL Checker websites will scan your page and list all HTTP resources found — far more convenient than checking each page individually in the browser Console. They crawl every resource on the page automatically, which is ideal for sites with many pages where you don't want to open DevTools page by page. The limitation is that these tools can only check pages reachable from the outside (public URLs); back-end pages or anything behind a login won't be scanned.
Another developer favorite is the Security tab in Chrome DevTools, which summarizes whether the page has mixed content, identifies which resource is responsible, and lets you click through to the details. The Network tab also helps you filter http:// requests by inspecting the Scheme or Protocol column.
Fixing Mixed Content Method by Method (DB Search-Replace, Protocol-relative, CSP)
Once you know which resources are still served over http://, it's time for the actual fix. There are several approaches, from fixing the root cause to patching the whole page at once. Pick the one that fits your situation.
Method 1: Search-Replace URLs in the Database (root-cause fix)
If http:// URLs are stored in the database (as with a CMS that keeps content as HTML), fixing the database directly is the most direct route. For a typical MySQL setup you can use an UPDATE statement like this (always back up first):
-- always back up the table first
-- mysqldump -u user -p dbname wp_posts > backup.sql
UPDATE wp_posts
SET post_content = REPLACE(post_content,
'http://yourdomain.com',
'https://yourdomain.com');
UPDATE wp_postmeta
SET meta_value = REPLACE(meta_value,
'http://yourdomain.com',
'https://yourdomain.com')
WHERE meta_value LIKE '%http://yourdomain.com%';
A word of caution: if data is stored as serialized values (such as certain options or widgets in WordPress), a raw REPLACE will corrupt the length counters inside the serialized string and break the data. Use a tool that handles serialized data correctly — like WP-CLI or a dedicated plugin — rather than running raw SQL against those fields.
# WP-CLI: safe with serialized data
wp search-replace 'http://yourdomain.com' 'https://yourdomain.com' \
--all-tables --dry-run
# review the result, then run for real (drop --dry-run)
wp search-replace 'http://yourdomain.com' 'https://yourdomain.com' \
--all-tables
Method 2: Protocol-relative URLs (//)
If you control the template code, you can change URLs to be protocol-relative by dropping http: and leaving just //. The browser will then pick the protocol matching the current page automatically — if the page is HTTPS, the resource loads over HTTPS too:
<!-- before: always forces http -->
<script src="http://cdn.example.com/lib.js"></script>
<!-- after: protocol-relative, follows the page -->
<script src="//cdn.example.com/lib.js"></script>
<!-- best: specify https explicitly -->
<script src="https://cdn.example.com/lib.js"></script>
Note: today it's recommended to specify https:// explicitly rather than use //, because nearly all sites are HTTPS now, and protocol-relative URLs can break when opening an HTML file locally (where the protocol is file://).
Method 3: CSP upgrade-insecure-requests (whole-page fix)
If http:// resources are scattered across many places and fixing them one by one is impractical, you can tell the browser to "upgrade" every request from http to https automatically using the Content Security Policy directive upgrade-insecure-requests. It can be set in a meta tag or an HTTP response header:
<!-- place in the <head> of every page -->
<meta http-equiv="Content-Security-Policy"
content="upgrade-insecure-requests">
# or as a header in .htaccess (Apache)
Header always set Content-Security-Policy "upgrade-insecure-requests"
# Nginx
add_header Content-Security-Policy "upgrade-insecure-requests";
This directive forces every same-origin resource specified as http:// to load over https instead — a fast, safe way to plug the problem. But treat it as a helper, not an excuse to skip fixing source URLs, because if a resource genuinely has no HTTPS version, it still won't load.
How to Fix Mixed Content in WordPress
Method 1: Really Simple SSL Plugin
This plugin is the easiest fix for WordPress users. Install and activate it with one click. The plugin will:
- Automatically change WordPress Address and Site Address to HTTPS
- Add a Force HTTPS redirect to .htaccess
- Fix mixed content using a Content Security Policy header with the
upgrade-insecure-requestsdirective
Method 2: Update WordPress URLs to HTTPS
- Go to WordPress Admin → Settings → General
- Change both WordPress Address (URL) and Site Address (URL) from http:// to https://
- Click Save Changes
Method 3: Search and Replace in the Database
Use the Better Search Replace plugin to find and replace http://yourdomain.com with https://yourdomain.com across the entire database. This addresses the root cause. Always back up before proceeding:
- Install and activate Better Search Replace
- Go to Tools → Better Search Replace
- Enter
http://yourdomain.comin the Search for field - Enter
https://yourdomain.comin the Replace with field - Select all database tables
- Run a Dry Run first to preview changes, then run the actual replacement
Method 4: Really Simple SSL Together with Better Search Replace
For WordPress, combining these two plugins is the most thorough recipe. Start with Really Simple SSL to force HTTPS, set up redirects, and enable upgrade-insecure-requests automatically. The plugin also includes a built-in mixed content scanner and warns you if there are resources it can't resolve. Then use Better Search Replace to sweep out http:// URLs buried deep in the database — it handles serialized data safely, unlike running raw SQL yourself.
The recommended order is: back up the database → run Better Search Replace as a Dry Run to see how many entries will change → run it for real → enable Really Simple SSL to handle headers and redirects → clear caches (both plugin cache and CDN) → reopen the DevTools Console to confirm no mixed content remains. Clearing the cache is critical, because pages cached before the fix may still contain http:// URLs, leading you to think the fix didn't work.
Fixing Mixed Content in Non-WordPress Sites
Search through all your HTML, CSS, and JavaScript code for URLs beginning with http:// and change them to https://. Alternatively, use protocol-relative URLs in the format //example.com/resource, which automatically inherit the page's current protocol without explicitly specifying http or https. Beyond HTML files, don't forget URLs embedded in CSS — especially url() in background-image and @import — as well as URLs that JavaScript builds dynamically, such as concatenated API endpoint strings, which are often overlooked because they don't appear directly in the HTML.
If you use a build system (such as Webpack or Vite), check any config that sets the base URL or public path to ensure it's https or relative, not a hardcoded http value. And if your site sits behind a reverse proxy or load balancer doing SSL termination, set the X-Forwarded-Proto header correctly so the application knows the request arrived over https and generates internal links as https accordingly.
CDN and Third-Party Resources
External services like Google Fonts, jQuery CDN, Facebook SDK, and chat widgets almost all support HTTPS now. Verify that any embed codes or CDN URLs you use in your site start with https:// rather than http://. If a third-party service does not support HTTPS, consider switching to an equivalent that does.
Frequently Asked Questions About Mixed Content
Why does my site still show "Not Secure" after installing SSL?
Because SSL makes the page's "main connection" HTTPS, but if the page still loads resources (images, scripts, CSS) over http://, the browser treats the whole page as not fully secure and removes the padlock. This isn't a problem with the SSL certificate itself — it's the resource URLs inside the page. Once every URL is changed to https, the padlock returns on its own.
Does mixed content affect SEO and Google rankings?
It has an indirect effect. Google treats HTTPS as a ranking factor, and a "Not Secure" warning raises bounce rates, which is a negative signal. In addition, blocked active mixed content can break analytics scripts or key features, hurting the user experience. Fixing it all is good for both security and SEO.
I fixed mixed content but some pages still warn. Why?
The most common cause is caching — browser cache, plugin cache, and CDN cache. Pages cached before the fix still contain http:// URLs. Clear every cache layer and retest in Incognito mode. Another cause is resources created dynamically by JavaScript or embedded in CSS, which a database search-replace may have missed.
Can upgrade-insecure-requests replace fixing the URLs entirely?
It can serve as a helper, but you shouldn't rely on it alone. The directive does upgrade http requests to https automatically, but if a source resource has no HTTPS version, it still won't load. The best approach is to fix the source URLs correctly and use upgrade-insecure-requests as an extra safety net.
Need an SSL Certificate for Your Website?
Paid SSL from 1,000 THB/year, or free Let's Encrypt included with AsiaGB Hosting.
View SSL Certificates