Self-signed vs CA-signed certificates
A self-signed certificate is its own issuer — nobody vouches for it, so every client must be configured to trust it individually. A CA-signed certificate is issued by an authority the client already trusts, so it is accepted with no configuration at all. The encryption is identical in both cases; the difference is purely about identity. Self-signed certificates are fine for local development and a poor fit for anything with users, because the usual workaround for the trust warning is to disable verification, which removes the protection TLS exists to provide.
The only difference #
openssl x509 -in self-signed.crt -noout -subject -issuer Expected output
subject=CN = localhost issuer=CN = localhost
openssl x509 -in ca-signed.crt -noout -subject -issuer Expected output
subject=CN = example.com issuer=C = US, O = Example CA, CN = Example Intermediate CA
That is the whole distinction. Everything else follows from it.
What is and is not different #
| Self-signed | CA-signed | |
|---|---|---|
| Encryption strength | Identical | Identical |
| TLS protocol version | Identical | Identical |
| Cipher suites | Identical | Identical |
| Trusted by default | No | Yes |
| Identity verified by a third party | No | Yes |
| Revocable | No | Yes, via CRL or OCSP |
| Cost | None | None, with a free CA |
| Client configuration needed | Per certificate, per machine | None |
Why the identity part matters #
Encryption without authentication protects you from a passive eavesdropper and not from an active one. An attacker who can intercept the connection presents their own self-signed certificate, and the client has no basis to tell it apart from yours — both are equally unvouched-for.
That is also why the usual workaround is so damaging. When a self-signed certificate produces a
warning, the fix people reach for is curl -k, verify=False or
NODE_TLS_REJECT_UNAUTHORIZED=0 — and those disable verification for every connection that code
makes, not just the one that prompted it.
When self-signed is the right choice #
- Local development.
localhostwith a certificate you generated is fine. - Throwaway test environments that no real data passes through.
- A root CA certificate. Every root is self-signed by definition — that is what makes it a root.
When it is not #
- Anything with real users, who will be taught to click through security warnings.
- Anything a mobile app connects to, where certificate handling is stricter and the workarounds are worse.
- Anything that needs revocation. A self-signed certificate cannot be revoked; if the key leaks your only options are to wait for expiry or manually remove it from every trust store it reached.
The middle path: a private CA #
For internal services, a private CA gives you the operational properties of a real CA without paying anyone. Trust the root once per machine, then issue as many certificates as you like:
| Self-signed | Private CA | Public CA | |
|---|---|---|---|
| Trust-store operations | One per certificate | One per machine, ever | None |
| Works for external users | No | No | Yes |
| Revocation | No | Yes | Yes |
| Setup effort | Lowest | Moderate, once | Low with ACME |
See create a root CA and sign a CSR with it.
Generating a self-signed certificate correctly #
If you do want one, the SAN extension is not optional — without it browsers reject the certificate even after you have trusted it:
openssl req -x509 -newkey rsa:2048 -nodes \
-keyout private.key -out certificate.crt -days 365 \
-subj "/CN=localhost" \
-addext "subjectAltName=DNS:localhost,IP:127.0.0.1" Full detail at generate a self-signed certificate.
Frequently asked questions
- Is a self-signed certificate less secure?
- The encryption is exactly the same — same algorithms, same key sizes, same TLS. What is missing is identity assurance. Nothing independent attests that the certificate belongs to who it claims to, so a client cannot distinguish the real server from an interceptor presenting a different self-signed certificate.
- Can I use a self-signed certificate in production?
- Only where you control every client and can install the certificate in each one — internal service-to-service traffic, for example. For anything with users, the browser warning trains people to click through security warnings, and the usual developer workaround is to disable verification entirely.
- How do I tell if a certificate is self-signed?
- Compare subject and issuer. If they are identical, it is self-signed.
openssl x509 -in certificate.crt -noout -subject -issueranswers it in one command. - What about Let's Encrypt?
- Let's Encrypt is a real, publicly trusted CA and its certificates are CA-signed. They are free and automatable, which removes most of the reasons people historically reached for self-signed certificates on public services. See how to get a free TLS certificate.
References
- CA/Browser Forum Baseline Requirements — what a publicly trusted CA is permitted to issue
- Mozilla CA certificate policy — the rules behind what reaches a browser trust store