Chrome and Firefox say “Not Secure” when the connection isn’t fully encrypted with HTTPS — not because you were hacked, but because the site has no SSL certificate, the certificate is expired or for the wrong domain, or the page loads something over plain HTTP. As of 2024 over 95% of web traffic is HTTPS (Google Transparency Report), so browsers now treat the insecure leftovers as warnings. This guide explains what “Not Secure” actually means, how SSL/TLS handshakes work in one round-trip, the 7 real causes, and the exact 10-minute fix for site owners and the safe choice for visitors.
- What it means: The page was loaded over
http://or overhttps://with a broken certificate or mixedhttp://sub-resources — the connection is not fully encrypted, authenticated, and integrity-checked. - Does it mean hacked? No — 90% of cases are configuration, not compromise: missing cert, expired (Let’s Encrypt 90 days, soon 47 days), domain mismatch (SAN), self-signed, incomplete chain, mixed content, or captive portal/antivirus interception.
- How HTTPS works: TLS (RFC 8446 TLS 1.3) does a 1-RTT handshake: ClientHello (ciphers + random) → ServerHello + Certificate + CertificateVerify → derive symmetric keys → all app data encrypted with AES-GCM/ChaCha20-Poly1305. See Cloudflare TLS handshake and MDN TLS.
- Visitor fix (30 sec): Don’t enter passwords/payments on Not Secure. Check clock, try incognito, check
https://version, avoid “Proceed anyway” on banks. Site owner fix (10 min): install cert (Let’s Encrypt via AutoSSL), force 301http→https, update URLs tohttps://, fix mixed content in Console, add HSTS + CSPupgrade-insecure-requests. - Check it: Click padlock → Certificate → issuer/expiry/SAN; DevTools → Console/Network for mixed content; external scan at SSL Labs; verify HSTS at hstspreload.org.
What “Not Secure” Actually Means (And What It Doesn’t)
“Not Secure” means the browser cannot confirm the connection is encrypted end-to-end — not that the site’s content was proven malicious. Chrome started marking all http:// pages Not Secure in July 2018 (Chrome 68); Firefox shows Warning: Potential Security Risk Ahead for certificate errors and a strikethrough padlock for plain HTTP. Both mean the same technical fact: no valid TLS session.
I see the confusion weekly: a small bakery site shows Not Secure and owners panic “were we hacked?” — checking reveals no certificate ever installed, just http:// with no redirect. Fixing takes 2 minutes in cPanel → SSL/TLS Status → Run AutoSSL, and the warning vanishes. No malware, no breach, just missing encryption.
Three states you’ll see:
- Lock (Secure):
https://with a valid certificate for that exact hostname, full chain, unexpired, modern TLS 1.2/1.3 — data is encrypted, authenticated, tamper-proof. - Not Secure (info triangle or grey): Page loaded over
http://or overhttps://but with mixedhttp://sub-resources — parts of the page are readable/modifiable by a network adversary (see MDN Mixed Content). Browsers still load it but warn before you type anything sensitive. - Your connection is not private (full-page interstitial):
NET::ERR_CERT_AUTHORITY_INVALID,ERR_CERT_DATE_INVALID,ERR_CERT_COMMON_NAME_INVALID— certificate invalid for that host, expired, self-signed, or untrusted CA — browser blocks until you explicitly bypass. This is the “hard” failure; the info-bar Not Secure is the “soft” warning.
Bottom line: Not Secure is about transport, not content. A perfect site on http:// is flagged; a scam site with a valid DV certificate can show a lock. The lock proves encryption and domain control, not trustworthiness — you still verify the domain spelling.
Quick History — Why Browsers Push So Hard
Google made HTTPS a ranking signal in 2014 and marked all http:// Not Secure from Chrome 68 (July 2018) because plain HTTP can be read/rewritten on Wi-Fi via SSL-stripping. HSTS + preload fix the downgrade; Let’s Encrypt now gives free 90-day auto-renewing certs, so cost is no excuse.
How HTTPS/SSL/TLS Actually Works — The 1-RTT Handshake in Plain English
HTTPS is HTTP over TLS — every byte is encrypted with a short-lived symmetric key that was negotiated without ever sending the key itself. TLS replaced the old SSL 3.0 in 1999 (RFC 7568 bans SSL), but we still say “SSL certificate” colloquially — it’s really a TLS certificate. Modern stacks should speak only TLS 1.2 and TLS 1.3; 1.0/1.1 are deprecated.
Three jobs, done in ~100ms before any page loads (Cloudflare TLS overview):
- Negotiate: Browser sends ClientHello — “I speak TLS 1.3, here are ciphers (AES-128-GCM, ChaCha20-Poly1305) and a random
client_random+ ephemeral key share.” Server replies ServerHello — “Let’s use TLS 1.3 + AES-128-GCM, here isserver_randomand my key share, plus my certificate chain.” See handshake details and MDN TLS. - Authenticate: Leaf → intermediate → root. Browser checks signatures, expiry, revocation, and SAN. If chain doesn’t end at trusted root →
ERR_CERT_AUTHORITY_INVALID. Servefullchain.pem, not justcert.pem. - Establish keys: ECDHE derives same session keys on both sides without sending the secret (forward secrecy) → both send
Finished→ app data flows encrypted with AEAD.
Client Server
| ClientHello (TLS1.3, ciphers, client_random, key_share) |
|---------------------------------------------------------->|
| ServerHello (chosen cipher, server_random, key_share) |
| {EncryptedExtensions} {Certificate} {CertificateVerify} |
| {Finished} |
|<----------------------------------------------------------|
| {Finished} — derive keys via HKDF, switch to AES-GCM |
|---------------------------------------------------------->|
| ========== Application Data (HTTPS) ================== |
TLS 1.3 (RFC 8446) cut the handshake from 2 round-trips to 1, removed weak ciphers (RC4/3DES/SHA1/RSA exchange), and supports 0-RTT for returning visitors — fast, but not for POSTs.
Certificate Chain — Why “Works in Chrome, Fails Elsewhere”
Leaf → intermediate (R3) → root (ISRG Root X1) baked into browser. Serve only leaf? Chrome may fetch missing via AIA/cache and look green, but curl/Node.js/Java fails unable to verify first cert. Fix: serve full chain; SSL Labs should say “Chain issues: None”.
The 7 Reasons Your Browser Says “Not Secure” (And the Exact Fix)
Nine of ten Not Secure cases fall into these seven — check them in this order, you’ll find the culprit in under 2 minutes.
| # | Cause | Browser Says | Who Sees It | Fix |
|---|---|---|---|---|
| 1 | No SSL at all | Not Secure (info i) | Everyone | Install cert (cPanel AutoSSL / Let’s Encrypt) |
| 2 | Expired | Your connection is not privateERR_CERT_DATE_INVALID | Everyone at once | Renew — check auto-renew, clock |
| 3 | Domain mismatch (SAN) | ERR_CERT_COMMON_NAME_INVALID | www vs non-www or subdomain | Reissue with all hostnames in SAN |
| 4 | Self-signed / Private CA | ERR_CERT_AUTHORITY_INVALID | Public visitors only | Public: replace with CA cert; Internal: install root |
| 5 | Incomplete chain | AUTHORITY_INVALID (strict clients) | Some visitors | Serve fullchain.pem + intermediates |
| 6 | Mixed content | Not Secure + Console warnings | HTTPS pages with http:// assets | Make all sub-resources https:// |
| 7 | Client / network | Not private / clock / MITM | Only you / that network | Fix clock, incognito, disable scan, captive login |
1. No SSL Certificate Installed
The site never had HTTPS — it loads only http://. Chrome marks any http:// Not Secure (stricter on inputs). Fix: install cert — cPanel AutoSSL or Let’s Encrypt Certbot. Verify https:// shows lock, then force all traffic to HTTPS.
2. Expired, Not Yet Valid, or Wrong Clock
Certificates have notBefore/notAfter — Let’s Encrypt is 90 days, tightening to ~47 days by 2029. When notAfter passes, everyone gets the interstitial at once — usually auto-renew failed (firewall blocked /.well-known/acme-challenge/ or server not reloaded). Also check client clock: months-off date makes a valid cert look expired. Renew 30 days before expiry and reload server.
3. Domain Mismatch — SAN Forgot www/Subdomain
Browsers check SAN, not legacy CN — if your hostname isn’t listed, it’s ERR_CERT_COMMON_NAME_INVALID. Example: cert for example.com without www → https://www.example.com fails. Fix: reissue with all hostnames in SAN (Let’s Encrypt up to 100). Wildcard *.example.com needs DNS challenge and doesn’t cover apex alone.
4. Self-Signed or Private CA Not Trusted
Self-signed = subject == issuer — signs itself, so no browser trusts it. Fine for NAS/localhost where you install your own root, bad for public sites. Corporate private CAs need root pushed via MDM/GPO — BYOD without it sees Not Secure. Public: replace with Let’s Encrypt; internal: distribute root.
5. Incomplete Chain — Missing Intermediate
Server sends only leaf, missing intermediate — strict clients can’t chain to the root. Chrome often hides it via AIA/cache, so it looks green on desktop but curl fails unable to get local issuer. Fix: serve fullchain.pem (Nginx ssl_certificate fullchain.pem) and check SSL Labs for “Chain issues: None”.
6. Mixed Content — One http:// Asset Breaks the Lock
HTTPS page loading a sub-resource over HTTP — browser downgrades whole page to Not Secure. One image/script/font is enough. Split into upgradable (images auto-upgraded) vs blockable (scripts blocked) per MDN Mixed Content.
7. Client / Network Interception
Sometimes only you see Not Secure — your device/network intercepts TLS. Triggers: wrong clock, stale cache/HSTS, extension, antivirus HTTPS scanning (re-signs with its CA), corporate proxy, or captive portal. Test: incognito + phone on mobile data — if both green, it’s your device/network, not the server.
Mixed Content Deep Dive — Why “I Installed SSL But Still Not Secure”
Installing a certificate encrypts the connection; it doesn’t rewrite a single URL inside your content — every http:// asset you saved before stays http:// and breaks the padlock.
Ranked by frequency I fix:
- Database-stored URLs (most common): WordPress posts, page-builder blocks, media library entries saved as
http://example.com/wp-content/uploads/logo.pngbefore HTTPS. One old logo URL breaks every page that uses the header. - Theme/plugin hardcoded assets: Header/footer/widget calling
http://fonts.googleapis.com/...or an icon font. - Third-party embeds: YouTube, maps, chat widgets, ad scripts still on
http://. - CDN in Flexible mode: Cloudflare Flexible serves
https://to visitors but talkshttp://to origin — the padlock looks green but origin leg is plain, and mixed upgrades fight. Switch to Full (Strict) with a valid cert on origin.
How to Find Every Insecure Resource in 30 Seconds
F12 → Console → reload. Red = blockable (script blocked), yellow = passive (padlock stripped). Copy the list; verify in Network tab filtered http://. For whole-site, use a crawler (Why No Padlock). See web.dev.
Fix It at the Source (Not Just With a Header)
- Replace at source: Swap
http://→https://or better, root-relative/uploads/logo.pngso it inherits the page’s scheme. In code, grephttp://in theme/plugins; in WordPress, set Settings → General → WordPress Address + Site Address tohttps://then run a safe search-replace:wp search-replace 'http://example.com' 'https://example.com' --all-tables --preciseor Better Search Replace plugin — backup first, never skip. - Check third-party hosts: If the external host has no HTTPS, host it yourself, replace it, or remove it — auto-upgrade will fail anyway.
- CSP safety net:
Content-Security-Policy: upgrade-insecure-requestsauto-upgrades stragglers tohttps://— net, not cure. Start Report-Only (MDN). - Clear every cache: Browser hard-refresh (
Ctrl+Shift+R), plugin cache, server cache, CDN purge — otherwise you’ll stare at a cached copy and think the fix failed.
How to Fix “Not Secure” — Site Owner 10-Minute Playbook
Do these in order — most sites go green after step 3.
Step 1 — Install or Renew the Certificate
In cPanel → SSL/TLS Status → select domain/www → Run AutoSSL; on a VPS → certbot --nginx -d example.com -d www.example.com (or --apache). Ensure it covers both apex and www in SAN. Confirm auto-renew: systemctl status certbot.timer and that firewall allows port 80 for HTTP-01 challenge.
Step 2 — Force 301 HTTP → HTTPS Everywhere
One canonical redirect, not a chain. Pick your canonical (I prefer https://example.com without www) and send everything there.
# Apache .htaccess (top, before WordPress rules)
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://example.com/$1 [R=301,L]
# Nginx server block
server {
listen 80;
server_name example.com www.example.com;
return 301 https://example.com$request_uri;
}
server {
listen 443 ssl;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# ... + HSTS below
}
Also set your app’s base URL to https:// (WordPress Settings → General, or WP_HOME/WP_SITEURL in wp-config.php if greyed out) so new links generate correctly.
Step 3 — Fix Mixed Content (See Above)
Console → list → search-replace DB → clear caches. Re-check incognito. One green image isn’t enough — every http:// sub-resource must be upgraded or removed.
Step 4 — Add HSTS + CSP Once Clean
Only after every page is 100% HTTPS without mixed warnings, add:
# HSTS: tell browsers to never use http:// for this host again
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
# CSP: auto-upgrade any straggler http:// sub-resources
Content-Security-Policy: upgrade-insecure-requests
Start HSTS max-age=31536000 (1y) → verify → then consider preload at hstspreload.org (needs includeSubDomains + 1y; removal takes months). Per MDN HSTS, HSTS disables click-through on cert errors — good for security, but an expired cert will lock users out.
Step 5 — Verify Outside Your Browser
SSL Labs → Grade A expected (TLS 1.2/1.3 only, no RC4/3DES, strong ciphers). Test both https://example.com and https://www.example.com, plus inner pages. Submit sitemap with https:// URLs and update Google Search Console to the HTTPS property. See all our web security explainers at Toolwasp — try our other security tools at toolwasp.com.
Visitor (Non-Owner) Quick Checks
Don’t enter sensitive data on Not Secure. Try: 1) Add https:// manually — does a secure version exist but you landed on http:// via old bookmark? 2) Incognito window (disables extensions) → still Not Secure? 3) Check clock → sync to automatic. 4) On public Wi-Fi, complete captive portal login or switch to mobile data. 5) For interstitials (ERR_CERT_DATE_INVALID etc.), only “Proceed” if you know it’s your own device/lab — never for banks/payment. If unsure, back out — legitimate public sites never ask you to add a certificate exception (per Firefox help).
How to Check SSL Yourself in 30 Seconds
Browser padlock → DevTools → SSL Labs — three clicks to certainty.
- Padlock: Chrome/Firefox → click lock/triangle in address bar → Connection is secure → Certificate is valid → see issuer (Let’s Encrypt/Cloudflare/DigiCert), subject (SAN list), expiry. On Not Secure, it says “Connection not secure” and lists why.
- DevTools:
F12→ Security tab (Chrome) or padlock details → View certificate; Console shows mixed content; Network showshttp://requests. Look forNET::ERR_CERT_COMMON_NAME_INVALIDetc. in console. - External: SSL Labs — enter domain without protocol → scans chain, TLS versions, ciphers, HSTS, and mixed grade. Want A/A+; B or C usually means old TLS 1.0/1.1 enabled or weak chain.
SSL vs TLS vs HTTPS — Say It Right
| Term | What It Is | Today |
|---|---|---|
| SSL | Secure Sockets Layer (Netscape, 90s), last SSL 3.0 | Deprecated, vuln (POODLE), banned by RFC 7568 — don’t enable |
| TLS | Transport Layer Security, successor (1.0 in 1999 → 1.3 now) | Use TLS 1.2 + 1.3 only; disable 1.0/1.1 |
| HTTPS | HTTP over TLS — HTTP inside the TLS tunnel | Every page + sub-resource should be HTTPS |
| Certificate | Leaves signed by intermediate → root (trust store) | DV (domain control) is fine for most; OV/EV are org vetting |
DV vs OV vs EV: DV proves you control the domain (email/DNS/HTTP challenge) — issued in minutes, free via Let’s Encrypt, and browser shows the same lock as OV/EV. OV/EV add org vetting but no extra encryption — EV green bar is gone from browsers. For public sites, DV is sufficient and automated; OV/EV only if your org requires it for policy.
HSTS, CSP, and Preload — Locking HTTPS In
Redirect alone isn’t enough — the first http:// request before the redirect can still be intercepted (SSL-stripping). HSTS solves it: after the first HTTPS visit, the browser remembers “only HTTPS for this host for 1 year” and auto-upgrades http:// before even sending it. Send MDN HSTS as Strict-Transport-Security: max-age=31536000; includeSubDomains; add preload only when ready for hardcoding at hstspreload.org — removal takes months. CSP upgrade-insecure-requests catches legacy http:// assets that HSTS doesn’t cover (sub-resources), but HSTS is the real fix for downgrade attacks. Together they ensure http:// never leaves the device.
When to Worry vs. When It’s (Relatively) Low Risk
Risk depends on what you were about to send.
- High risk — back out: Not Secure on login, checkout, payment, medical/government forms, or any interstitial (date invalid, authority invalid, name mismatch) on a bank/email — credentials/payment can be read or rewritten in transit. Don’t enter data, don’t bypass.
- Medium — fix soon: Blog with Not Secure but no input — less direct theft but still allows injection (attacker can modify images/scripts) and hurts SEO (Google uses HTTPS as a ranking signal; indexed
http://splits equity). - Lower — but still fix: Mixed passive content (image upgraded) on an otherwise secure page — browser auto-fixed it, but padlock stays away and future browsers will block more. Treat it as tech debt, not an emergency.
Rule: if the page asks for password/card, Not Secure = don’t proceed. Read-only blog with no inputs is lower risk but still fix today.
Practice Lab — 5 Minutes from Not Secure to Lock
Lab (on your own domain or test subdomain):
1) Reproduce: visit http://example.com → see Not Secure → try https://example.com → note difference
2) Inspect: click padlock → Certificate → note issuer/SAN/expiry → DevTools Console → spot mixed http:// asset
3) Fix redirect: add 301 http→https in .htaccess/Nginx → incognito reload → http should 301 to https
4) Fix mixed: change one http:// image → https:// → reload → console warning disappears
5) Harden: add HSTS (max-age=31536000) + CSP upgrade-insecure-requests → SSL Labs → expect A
# Verify: https://www.ssllabs.com/ssltest/analyze.html?d=example.com and https://hstspreload.org/
You just practiced the owner workflow: reproduce → inspect → redirect → mixed fix → harden → verify. One staging run makes the next migration 2 minutes.
Frequently Asked Questions
Why does my browser say “Not Secure” even though I have an SSL certificate?
Your certificate likely covers the page but not everything on it. The #1 cause after installing SSL is mixed content — one image, script, or font still on http:// breaks the padlock even though https:// loads. Open DevTools → Console → fix each http:// asset to https:// via search-replace, clear caches, and verify in incognito. Also check that http:// 301s to https:// and both www and non-www are in the cert’s SAN (Firefox error meanings).
Does “Not Secure” mean my site was hacked?
No — almost never. It means the connection isn’t fully encrypted, not that content is malicious. Hacked sites can show a lock if they have a valid cert; perfectly clean sites show Not Secure if they’re on http://. That said, an attacker intercepting plain HTTP could inject content, so you should still fix it quickly and avoid entering sensitive data on Not Secure pages. Check your server logs and security headers after fixing.
What’s the difference between SSL, TLS, and HTTPS?
SSL is the 1990s predecessor (now banned), TLS is the current protocol (1.2/1.3), HTTPS is HTTP inside TLS. When people say “SSL certificate” they mean a TLS certificate for HTTPS. Use TLS 1.2+ only; see MDN TLS and RFC 8446. A certificate is the server’s public key + identity signed by a CA — the browser trusts it if the chain ends at a root in its store.
How do I fix “Not Secure” on WordPress?
1) Install cert (cPanel AutoSSL or Certbot for example.com + www). 2) Settings → General set WordPress Address + Site Address to https://. 3) Add 301 http→https in .htaccess (code above). 4) Run Better Search Replace http://example.com → https://example.com on all tables (backup first). 5) Clear plugin/CDN/browser caches. 6) Add CSP upgrade-insecure-requests and, once clean, HSTS (web.dev mixed content).
How long does it take to fix “Not Secure”?
Minutes if the cert is valid: redirect + mixed content search-replace → padlock on next incognito load. If no cert, add 5–10 minutes for issuance (Let’s Encrypt via AutoSSL is instant). After fixing, purge CDN/cache; SSL Labs shows Green A within one scan, but Google Search Console and HSTS preload take days/weeks to reflect indexing and hardcoding. Keep auto-renew on — most “suddenly Not Secure” cases months later are just an expired 90-day cert.
Is it safe to click “Back to safety” or “Proceed anyway”?
On a banking, email, or payment interstitial (ERR_CERT_DATE_INVALID etc.), don’t proceed — it could be a misconfiguration or interception that exposes what you type. On your own lab/localhost or a known internal tool with a private CA you installed, proceeding after verifying the fingerprint is expected. Public sites never need a permanent exception — per Firefox guidance, a public site asking for an exception is suspicious.
What is HSTS and do I need it?
HTTP Strict Transport Security tells browsers to only use https:// for your host for a year even if a link says http://, preventing SSL-stripping downgrade on the first request after the header is set. Set Strict-Transport-Security: max-age=31536000; includeSubDomains once 100% HTTPS is clean. Submit to hstspreload.org with preload for first-visit protection — but only when every subdomain supports HTTPS, as removal takes months (MDN HSTS).
How do I check if my site’s SSL is correctly installed?
Click padlock → Certificate is valid → check issuer, SAN covers www + apex, notAfter in future. Then scan at SSL Labs for chain issues, TLS versions, HSTS, and grade. Also open DevTools → Console → no mixed content warnings, and test both https://example.com and https://www.example.com in incognito so cache doesn’t lie.
Last updated: September 1, 2026 • Author: Toolwasp Team • Sources verified Sep 1, 2026: MDN TLS, MDN Mixed Content, Let’s Encrypt How It Works, Cloudflare Handshake, RFC 8446 TLS 1.3, Google HTTPS Transparency, SSL Labs, HSTS Preload. Explore more guides at Toolwasp.