# How to Use mkcert Certificates with Java Applications: A Complete keytool Integration Guide

> Integrate mkcert certificates with Java applications using keytool. Easily add mkcert root CA to your trust store and generate PKCS12 bundles for seamless JVM TLS.

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

---

**Set the `JAVA_HOME` environment variable and run `mkcert -install` to automatically add the mkcert root CA to your Java trust store, then generate PKCS#12 bundles with `mkcert -p12` for seamless TLS in JVM applications.**

mkcert (FiloSottile/mkcert) generates locally-trusted development certificates by maintaining a private root Certificate Authority. When `JAVA_HOME` is properly configured, mkcert automatically integrates with the Java **keytool** utility to install this root CA into the system `cacerts` keystore, eliminating SSL handshake errors during local development without manual certificate management.

## How mkcert Detects and Modifies the Java Trust Store

According to the mkcert source code in [`truststore_java.go`](https://github.com/FiloSottile/mkcert/blob/main/truststore_java.go), the tool detects Java installations by checking the `JAVA_HOME` environment variable. When present, mkcert locates the `keytool` binary and the `cacerts` file within `$JAVA_HOME/lib/security/` (or the legacy `jre` subdirectory on older installations).

The integration relies on four core functions defined in the source:

- **`checkJava()`**: Executes `keytool -list` to verify if the mkcert root CA is already present by comparing SHA-1 or SHA-256 fingerprints of the stored certificates.
- **`installJava()`**: Builds and runs the `keytool -importcert` command to add `rootCA.pem` using the unique alias returned by `caUniqueName()`.
- **`execKeytool()`**: Handles command execution with automatic `sudo` escalation on Unix systems if permission is denied when writing to the system trust store.
- **`uninstallJava()`**: Removes the CA alias from the keystore when running `mkcert -uninstall`.

The default keystore password is hard-coded as **`changeit`** in [`truststore_java.go`](https://github.com/FiloSottile/mkcert/blob/main/truststore_java.go) (line 31), which mkcert uses both for importing the CA into the Java trust store and for protecting generated PKCS#12 files.

## Installing the mkcert Root CA for Java

Before generating certificates for your applications, install the mkcert root CA into the Java trust store:

```bash
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
mkcert -install

```

Internally, as implemented in `installJava()` at `truststore_java.go#L81-L89`, this executes the equivalent of:

```bash
keytool -importcert -noprompt \
  -keystore $JAVA_HOME/lib/security/cacerts \
  -storepass changeit \
  -file $(mkcert -CAROOT)/rootCA.pem \
  -alias "mkcert development CA"

```

If `checkJava()` detects the CA fingerprint is already present in the keystore, the installation is skipped to avoid duplicate entries. The [`main.go`](https://github.com/FiloSottile/mkcert/blob/main/main.go) file (lines 97-100) controls whether the Java trust store is touched based on environment detection.

## Generating and Using Certificates in Java Applications

Once the root CA is trusted by the JVM, create certificates for your specific development domains.

### Creating a PKCS#12 Bundle

Generate a certificate and private key packaged for Java consumption:

```bash
mkcert -p12 localhost 127.0.0.1 ::1

```

This produces `localhost+3.p12` containing the leaf certificate and its private key, encrypted with the password `changeit`. This format is ready for direct use with Java's `KeyStore` API without additional conversion.

### Loading the Keystore Programmatically

Load the PKCS#12 file in your Java application code:

```java
import java.io.FileInputStream;
import java.security.KeyStore;

public class SslConfig {
    public static KeyStore loadMkcertKeystore() throws Exception {
        KeyStore ks = KeyStore.getInstance("PKCS12");
        try (FileInputStream fis = new FileInputStream("localhost+3.p12")) {
            ks.load(fis, "changeit".toCharArray());
        }
        return ks;
    }
}

```

### Configuring JVM SSL Properties

For servers like Spring Boot, Jetty, or Tomcat, pass the keystore via system properties without writing code:

```bash
java -Djavax.net.ssl.keyStore=localhost+3.p12 \
     -Djavax.net.ssl.keyStorePassword=changeit \
     -Djavax.net.ssl.keyStoreType=PKCS12 \
     -jar application.jar

```

## Adding the CA to Custom Client Trust Stores

For Java clients using isolated trust stores rather than the global `cacerts` file, manually import the root CA:

```bash
keytool -importcert -keystore client-truststore.jks \
  -storepass changeit \
  -file $(mkcert -CAROOT)/rootCA.pem \
  -alias mkcert-root

```

Clients then reference this store with `-Djavax.net.ssl.trustStore=client-truststore.jks` to validate server certificates issued by mkcert.

## Summary

- **mkcert** automatically integrates with Java when `JAVA_HOME` is set, as implemented in [`truststore_java.go`](https://github.com/FiloSottile/mkcert/blob/main/truststore_java.go) and coordinated by [`main.go`](https://github.com/FiloSottile/mkcert/blob/main/main.go).
- The **`checkJava()`** and **`installJava()`** functions manage root CA installation using **keytool** with the default password **`changeit`**.
- Use **`mkcert -p12`** to generate PKCS#12 bundles compatible with Java's `KeyStore.getInstance("PKCS12")` loader.
- Both the generated keystores and the Java system trust store use the password **`changeit`** by default.
- The root CA PEM file is located at **`$(mkcert -CAROOT)/rootCA.pem`** for manual import scenarios.

## Frequently Asked Questions

### Does mkcert work with all Java versions and distributions?

Yes. mkcert detects any JDK or JRE through the `JAVA_HOME` environment variable and locates the `cacerts` file regardless of whether you use OpenJDK, Oracle JDK, or Amazon Corretto. The `keytool` command syntax has remained consistent since Java 8, and mkcert's `execKeytool()` function handles execution across platforms, ensuring compatibility from Java 8 through Java 21 and beyond.

### What is the default password for mkcert-generated PKCS#12 files?

The default password is **`changeit`**. This value is defined as the `storePass` constant in [`truststore_java.go`](https://github.com/FiloSottile/mkcert/blob/main/truststore_java.go) and is used both when mkcert creates the PKCS#12 bundle via the `-p12` flag and when it imports the root CA into the Java trust store via `installJava()`.

### How do I remove the mkcert CA from my Java installation?

Run `mkcert -uninstall` with `JAVA_HOME` set to your JDK path. This triggers the **`uninstallJava()`** function in [`truststore_java.go`](https://github.com/FiloSottile/mkcert/blob/main/truststore_java.go), which executes `keytool -delete` to remove the CA alias from the `cacerts` keystore. Alternatively, manually run: `keytool -delete -alias <ca-unique-name> -keystore $JAVA_HOME/lib/security/cacerts -storepass changeit`, replacing `<ca-unique-name>` with the output of `mkcert -CAROOT` inspection.

### Can I use mkcert certificates inside Docker containers running Java?

Yes. Mount the generated PKCS#12 file into the container and pass it via JVM system properties, or copy the `rootCA.pem` into a custom trust store during the Docker build. Ensure the container's Java installation trusts the CA by importing it with `keytool` during image construction, or mount the host's modified `cacerts` file if the Java versions match exactly.