# mkcert Default Key Generation Parameters: RSA 2048 vs 3072 Explained

> Understand mkcert key generation defaults. Learn why mkcert uses RSA 2048 for leaf certificates and RSA 3072 for root CAs, and explore ECDSA alternatives.

- Repository: [Filippo Valsorda/mkcert](https://github.com/FiloSottile/mkcert)
- Tags: deep-dive
- Published: 2026-03-05

---

**mkcert generates RSA 2048-bit keys for leaf certificates by default, but uses RSA 3072-bit keys for the root CA, unless the `-ecdsa` flag is specified to use P-256 elliptic curve cryptography instead.**

The mkcert tool simplifies local HTTPS development by automatically creating and trusting locally-signed certificates. Understanding its default key generation parameters helps developers assess security trade-offs and compliance requirements when deploying local development environments.

## How mkcert Generates Keys by Default

When you run mkcert without the `-ecdsa` flag, it creates **RSA keys** through the `generateKey` function in [`cert.go`](https://github.com/FiloSottile/mkcert/blob/main/cert.go). The bit length varies based on whether the key is intended for a leaf certificate or the root Certificate Authority (CA).

### Leaf Certificates: RSA 2048

For standard domain certificates (leaf certificates), mkcert defaults to **2048-bit RSA keys**. When you execute `mkcert example.com`, the tool calls `makeCert()`, which invokes `generateKey(false)`:

```go
// From makeCert() in cert.go (lines 55-57)
priv, err := m.generateKey(false)

```

Inside `generateKey()`, when `rootCA` is `false`, the function returns:

```go
return rsa.GenerateKey(rand.Reader, 2048)

```

This 2048-bit default balances security with performance for temporary development certificates.

### Root CA: RSA 3072

When installing a new local CA via `mkcert -install`, the tool generates a **3072-bit RSA key** for the root certificate. The `newCA()` function calls `generateKey(true)`:

```go
// From newCA() in cert.go (lines 110-115)
priv, err := m.generateKey(true)

```

In `generateKey()`, the `true` parameter triggers the higher bit length:

```go
return rsa.GenerateKey(rand.Reader, 3072)

```

The stronger 3072-bit key for the root CA provides enhanced security for the trust anchor, following CA/Browser Forum baseline requirements that recommend minimum 2048-bit keys but prefer 3072-bit or higher for root certificates.

## The generateKey Function in cert.go

The conditional logic resides in [`cert.go`](https://github.com/FiloSottile/mkcert/blob/main/cert.go) at lines 66-74, where `generateKey` determines which cryptographic parameters to use based on the `rootCA` boolean and the global ECDSA flag:

```go
func (m *mkcert) generateKey(rootCA bool) (crypto.PrivateKey, error) {
    if m.ecdsa {
        return ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
    }
    if rootCA {
        return rsa.GenerateKey(rand.Reader, 3072)
    }
    return rsa.GenerateKey(rand.Reader, 2048)
}

```

This implementation clearly shows the three code paths: ECDSA P-256 when the flag is set, RSA 3072 for root CA creation, and RSA 2048 for all other certificates.

## ECDSA Alternative: P-256 Curve

When you specify the `-ecdsa` flag, mkcert bypasses RSA entirely and generates **ECDSA keys using the P-256 elliptic curve** (also known as secp256r1 or prime256v1). This path executes regardless of whether the key is for a root CA or leaf certificate:

```go
return ecdsa.GenerateKey(elliptic.P256(), rand.Reader)

```

P-256 provides equivalent security to RSA 3072 but with significantly smaller key sizes and faster operations. However, some legacy systems may not support ECDSA, which is why RSA 2048 remains the default for leaf certificates.

## Summary

- **Leaf certificates** use **RSA 2048-bit** keys by default, generated via `generateKey(false)` in [`cert.go`](https://github.com/FiloSottile/mkcert/blob/main/cert.go).
- **Root CA certificates** use **RSA 3072-bit** keys, generated via `generateKey(true)` when running `mkcert -install`.
- **ECDSA P-256** keys are generated when the `-ecdsa` flag is specified, bypassing RSA entirely.
- The logic resides in the `generateKey` function at lines 66-74 of [`cert.go`](https://github.com/FiloSottile/mkcert/blob/main/cert.go), which checks the `rootCA` boolean and global ECDSA configuration.

## Frequently Asked Questions

### Why does mkcert use RSA 3072 for the root CA but 2048 for leaf certificates?

The root CA serves as the trust anchor for all locally-generated certificates, requiring stronger cryptographic protection to prevent compromise of the entire PKI hierarchy. The 3072-bit key provides security margins appropriate for a long-lived root certificate, while 2048-bit keys offer sufficient security for temporary development certificates with better performance characteristics.

### Can I change the default RSA key size in mkcert?

No, the RSA key sizes are hardcoded in the `generateKey` function in [`cert.go`](https://github.com/FiloSottile/mkcert/blob/main/cert.go). To use different key lengths, you would need to modify the source code and recompile mkcert, changing the `3072` or `2048` parameters in the `rsa.GenerateKey` calls. There are no command-line flags to adjust RSA key sizes at runtime.

### What happens when I use the -ecdsa flag?

When you specify `-ecdsa`, mkcert generates ECDSA keys using the P-256 elliptic curve instead of RSA keys. This applies to both root CA and leaf certificate generation. P-256 provides security comparable to RSA 3072 but with smaller key sizes and faster cryptographic operations. Note that some older systems or specific applications may not support ECDSA certificates.

### Where is the key generation logic located in the mkcert source code?

The key generation logic resides in the `generateKey` method in [`cert.go`](https://github.com/FiloSottile/mkcert/blob/main/cert.go) at lines 66-74. This function checks whether the `ecdsa` field is set on the `mkcert` struct, then falls back to RSA generation with conditional logic based on the `rootCA` boolean parameter. The `newCA()` function (lines 110-115) and `makeCert()` function (lines 55-57) serve as the entry points that invoke `generateKey` with the appropriate boolean values.