All Tools View Categories Blog About Contact Privacy

Why Does My Browser Say "Not Secure"? SSL/HTTPS Explained

Why Does My Browser Say "Not Secure"? SSL/HTTPS Explained

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.

TL;DR — Why Does My Browser Say “Not Secure”?
  • What it means: The page was loaded over http:// or over https:// with a broken certificate or mixed http:// 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 301 http→https, update URLs to https://, fix mixed content in Console, add HSTS + CSP upgrade-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.
why browser says not secure meaning http vs https not secure warning chrome firefox

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 over https:// but with mixed http:// 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.

how tls handshake works clienthello serverhello certificate https explained diagram

Three jobs, done in ~100ms before any page loads (Cloudflare TLS overview):

  1. 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 is server_random and my key share, plus my certificate chain.” See handshake details and MDN TLS.
  2. Authenticate: Leaf → intermediate → root. Browser checks signatures, expiry, revocation, and SAN. If chain doesn’t end at trusted root → ERR_CERT_AUTHORITY_INVALID. Serve fullchain.pem, not just cert.pem.
  3. 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.

7 reasons browser says not secure missing expired domain mismatch mixed content table
#CauseBrowser SaysWho Sees ItFix
1No SSL at allNot Secure (info i)EveryoneInstall cert (cPanel AutoSSL / Let’s Encrypt)
2ExpiredYour connection is not private
ERR_CERT_DATE_INVALID
Everyone at onceRenew — check auto-renew, clock
3Domain mismatch (SAN)ERR_CERT_COMMON_NAME_INVALIDwww vs non-www or subdomainReissue with all hostnames in SAN
4Self-signed / Private CAERR_CERT_AUTHORITY_INVALIDPublic visitors onlyPublic: replace with CA cert; Internal: install root
5Incomplete chainAUTHORITY_INVALID (strict clients)Some visitorsServe fullchain.pem + intermediates
6Mixed contentNot Secure + Console warningsHTTPS pages with http:// assetsMake all sub-resources https://
7Client / networkNot private / clock / MITMOnly you / that networkFix 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 wwwhttps://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.

mixed content fix http vs https resources upgrade insecure requests console

Ranked by frequency I fix:

  1. Database-stored URLs (most common): WordPress posts, page-builder blocks, media library entries saved as http://example.com/wp-content/uploads/logo.png before HTTPS. One old logo URL breaks every page that uses the header.
  2. Theme/plugin hardcoded assets: Header/footer/widget calling http://fonts.googleapis.com/... or an icon font.
  3. Third-party embeds: YouTube, maps, chat widgets, ad scripts still on http://.
  4. CDN in Flexible mode: Cloudflare Flexible serves https:// to visitors but talks http:// 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.png so it inherits the page’s scheme. In code, grep http:// in theme/plugins; in WordPress, set Settings → General → WordPress Address + Site Address to https:// then run a safe search-replace: wp search-replace 'http://example.com' 'https://example.com' --all-tables --precise or 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-requests auto-upgrades stragglers to https:// — 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.

how to fix not secure checklist install ssl redirect https mixed content hsts

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 shows http:// requests. Look for NET::ERR_CERT_COMMON_NAME_INVALID etc. 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

TermWhat It IsToday
SSLSecure Sockets Layer (Netscape, 90s), last SSL 3.0Deprecated, vuln (POODLE), banned by RFC 7568 — don’t enable
TLSTransport Layer Security, successor (1.0 in 1999 → 1.3 now)Use TLS 1.2 + 1.3 only; disable 1.0/1.1
HTTPSHTTP over TLS — HTTP inside the TLS tunnelEvery page + sub-resource should be HTTPS
CertificateLeaves 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.