Fix java.security.UnrecoverableKeyException: Cannot recover key

Fix java.security.UnrecoverableKeyException: Cannot recover key by aligning keystore and private key passwords in Tomcat, Spring Boot, and KeyManagerFactory.

Published

Updated

Read time 7 min read

Reviewed byDeepak Prasad

Fix Java UnrecoverableKeyException cannot recover key banner with keystore and private key

You already see it in Tomcat, Confluence, Spring Boot, or a plain Java SSL stack trace: java.security.UnrecoverableKeyException: Cannot recover key. The keystore file usually opens fine — the failure happens one step later when Java tries to decrypt the private key for your TLS alias.

Use the table below to jump to the cause that matches your setup. Each section explains why it happens and what to change. If keytool -list fails before you reach this error, start with Fix keystore tampered or password incorrect instead.

Tested on: Ubuntu 26.04 LTS; OpenJDK 25.0.3; kernel 7.0.0-27-generic.


What the error actually means

KeyManagerFactory.init(keystore, password) needs a password to decrypt each PrivateKeyEntry. If that password does not match the key password set when the entry was created, the JVM throws:

text
java.security.UnrecoverableKeyException: Cannot recover key

In Tomcat logs the same root exception is often wrapped:

text
Caused by: java.lang.IllegalArgumentException: Cannot recover key
...
Caused by: java.security.UnrecoverableKeyException: Cannot recover key

This is not a corrupt certificate chain problem and not a truststore issue. Java recovered the keystore container but not the private key inside the alias your connector uses.


Find your cause

Likely cause Clues Go to
Store password ≠ key password keytool -list works; Tomcat or KeyManagerFactory.init fails; JKS created with different -keypass Key password mismatch
Tomcat certificateKeyPassword missing or wrong certificateKeystorePassword is correct; certificateKeyPassword is omitted or stale in server.xml Tomcat connector passwords
Spring Boot key password wrong server.ssl.key-store-password correct; server.ssl.key-password missing or wrong Spring Boot SSL passwords
Wrong alias Multiple PrivateKeyEntry rows; connector points at the wrong alias Wrong alias or multiple keys
Post-renewal key password drift New cert imported; old key password still in app config After certificate renewal

Key password does not match store password

JKS allows a store password (-storepass) and a per-alias key password (-keypass) to differ. keytool -genkeypair accepts both:

bash
keytool -genkeypair -alias tomcat -keyalg RSA -keystore server.jks -storetype JKS \
  -storepass storepass -keypass keypass123 \
  -dname "CN=localhost" -noprompt

Listing the keystore only checks the store password — it still succeeds:

text
Keystore type: JKS
Keystore provider: SUN

Your keystore contains 1 entry

Tomcat-style loading uses KeyManagerFactory.init with a single password for private keys. If the app passes the store password while the entry was protected with keypass123, initialization fails:

text
Keystore loaded OK
Exception in thread "main" java.security.UnrecoverableKeyException: Cannot recover key
	at java.base/sun.security.provider.KeyProtector.recover(KeyProtector.java:293)
	at java.base/sun.security.provider.JavaKeyStore.engineGetKey(JavaKeyStore.java:162)
	...
	at java.base/javax.net.ssl.KeyManagerFactory.init(KeyManagerFactory.java:269)

Passing the correct key password succeeds:

text
Keystore loaded OK
KeyManagerFactory initialized OK

Fix by aligning passwords. Change the key password to match the store password (typical for Tomcat):

NOTE
Avoid typing real keystore and key passwords directly into shell history on production systems. Prefer an interactive prompt, protected environment variable, secret manager, or temporary root-only script.
bash
keytool -keypasswd -alias tomcat -keystore server.jks \
  -storepass storepass -keypass keypass123 -new storepass -noprompt
NOTE
Use keytool -keypasswd mainly for JKS keystores. For PKCS12, modern keytool commonly expects the key password and store password to stay aligned, and may warn that a separate -keypass is ignored. If a PKCS12 file still fails with Cannot recover key, recreate or re-export the .p12 with a known password and update the app config.

After alignment, KeyManagerFactory.init with the store password works again. More rotation patterns in Change alias, password, and delete entries.

In Java/keytool workflows, PKCS12 is normally configured with the same store and key password — mismatches are less common but the same Cannot recover key message appears if the app supplies the wrong decryption password for the alias.


Tomcat connector passwords

Tomcat reads the identity keystore through JSSE. On the Certificate element in server.xml (or equivalent), these attributes matter:

Attribute Role
certificateKeystoreFile Path to the keystore
certificateKeystorePassword Store password (legacy docs: keystorePass)
certificateKeyPassword Key password for the alias (legacy: keyPass)
certificateKeyAlias Alias to load (recommended when several keys exist)

You hit Cannot recover key when:

  • certificateKeyPassword is wrong while the store password is right
  • certificateKeyPassword is omitted and Tomcat reuses the store password, but the alias was created with a different -keypass
  • The connector targets the wrong alias and the reused password does not fit that entry

Fix options:

  1. Set certificateKeyPassword to the real key password for the alias, or
  2. Run keytool -keypasswd so the alias key password matches what Tomcat passes (often the same as the store password), or
  3. Set certificateKeyAlias explicitly and match passwords for that alias only

See Configure Tomcat SSL with keytool for a clean PKCS12 connector layout.


Spring Boot SSL passwords

Spring Boot separates store and key passwords:

properties
server.ssl.key-store=/path/to/keystore.p12
server.ssl.key-store-password=store-secret
server.ssl.key-store-type=PKCS12
server.ssl.key-alias=tomcat
server.ssl.key-password=key-secret

If key-password is omitted, Spring may reuse the store password depending on version and keystore type. If you generated the PKCS12 with different store and key passwords (unusual but possible in JKS conversion paths), startup fails with UnrecoverableKeyException.

Canonical environment mapping for the store password is SERVER_SSL_KEYSTOREPASSWORD; verify resolved properties map to server.ssl.key-store-password and server.ssl.key-password in your deployment layer.


Wrong alias or multiple private keys

KeyManagerFactory.init walks private-key entries. If the keystore holds several aliases with different key passwords and the factory is initialized with one password, decryption fails for at least one entry.

Check aliases:

bash
keytool -list -v -keystore server.jks -storepass storepass
text
tomcat, Jul 3, 2026, PrivateKeyEntry,
oldhost, Jan 1, 2025, PrivateKeyEntry,

Only PrivateKeyEntry aliases can be used as a TLS server identity. A trustedCertEntry is for truststore CA certificates and cannot provide the server private key.

After a hostname or cert renewal, an old PrivateKeyEntry may remain. Either:

  • Point the connector at the correct alias (certificateKeyAlias / server.ssl.key-alias), or
  • Delete obsolete aliases with keytool -delete, or
  • Align every remaining private key to the password your app uses

After certificate renewal

Renewal workflows often import a new certificate onto an existing alias or add a new alias with a fresh -keypass. The store password in server.xml or Spring config is updated, but the key password for the alias is not.

Symptoms match Confluence and Tomcat KB patterns: keystore opens, connector password was rotated, startup still reports Cannot recover key.

Before changing passwords, confirm the active alias with keytool -list -v and match it with certificateKeyAlias or server.ssl.key-alias.

Fix:

bash
keytool -keypasswd -alias confluence -keystore confluence.jks \
  -storepass NEW_STORE -keypass OLD_KEY -new NEW_STORE -noprompt

keytool -storepasswd -keystore confluence.jks \
  -storepass OLD_STORE -new NEW_STORE -noprompt

Update certificateKeystorePassword and certificateKeyPassword (or Spring equivalents) to NEW_STORE before restart.


Quick lab reproduction

To see the Tomcat-style failure in isolation, create a JKS keystore with different store and key passwords, then initialize KeyManagerFactory with only the store password.

Create the keystore:

bash
mkdir -p ~/unrecoverable-key-lab && cd ~/unrecoverable-key-lab

keytool -genkeypair -alias tomcat -keyalg RSA -keystore mismatch.jks -storetype JKS \
  -storepass storepass -keypass keypass123 \
  -dname "CN=localhost" -noprompt

Save this program as LoadKeystore.java:

java
import java.io.FileInputStream;
import java.security.KeyStore;
import javax.net.ssl.KeyManagerFactory;

public class LoadKeystore {
  public static void main(String[] args) throws Exception {
    KeyStore ks = KeyStore.getInstance("JKS");
    try (FileInputStream in = new FileInputStream("mismatch.jks")) {
      ks.load(in, "storepass".toCharArray());
    }
    KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
    kmf.init(ks, "storepass".toCharArray());
    System.out.println("KeyManagerFactory initialized OK");
  }
}

Compile and run:

bash
javac LoadKeystore.java
java LoadKeystore

Expected failure when store and key passwords differ:

text
Exception in thread "main" java.security.UnrecoverableKeyException: Cannot recover key

Align the key password, then rerun:

bash
keytool -keypasswd -alias tomcat -keystore mismatch.jks \
  -storepass storepass -keypass keypass123 -new storepass -noprompt

java LoadKeystore
text
KeyManagerFactory initialized OK

Run only in a throwaway directory — not on production keystores.


Distinguish from other keystore errors

Error When it fails Guide
UnrecoverableKeyException: Cannot recover key Private key decrypt with wrong key password This page
Public keys in reply and keystore don't match CSR alias ≠ import alias Public keys mismatch
PKIX path building failed Trust chain missing at TLS handshake PKIX troubleshooting

References


Summary

java.security.UnrecoverableKeyException: Cannot recover key means the keystore opened but Java could not decrypt the private key for your TLS alias. Start with the cause table: mismatched store and key passwords, missing Tomcat certificateKeyPassword, wrong Spring server.ssl.key-password, a bad alias, or stale passwords after renewal. Use keytool -keypasswd to align the alias, update connector or Spring config, and distinguish this from store-password errors that fail earlier at KeyStore.load.


Frequently Asked Questions

1. What does UnrecoverableKeyException Cannot recover key mean?

Java opened the keystore with the store password but could not decrypt a PrivateKeyEntry with the key password supplied to KeyManagerFactory.init or an equivalent SSL setup path. The private key password is wrong, missing in config, or different from what Tomcat assumes when keyPass is omitted.

2. Is this the same as Keystore was tampered with or password was incorrect?

No. Tampered or password incorrect fails while loading the keystore file. Cannot recover key means the store password worked and the failure happened when reading a specific alias private key. See the keystore tampered guide if keytool -list itself fails.

3. Do Tomcat keystorePass and keyPass have to match?

Tomcat can use different values when keyPass is set correctly in server.xml. Many teams still keep them identical because KeyManagerFactory.init accepts one password for all private keys and omitting keyPass makes Tomcat reuse the keystore password. Mismatches are a common cause of this error.

4. How do I fix Cannot recover key after a certificate renewal?

Confirm the renewed alias still uses the key password your app passes to KeyManagerFactory. If you imported a new key pair with a different -keypass, run keytool -keypasswd to align it, or update certificateKeyPassword and keyPass in Tomcat or server.ssl.key-password in Spring Boot.

5. Can keytool -list work while Tomcat still fails with Cannot recover key?

Yes. keytool -list only needs the store password. Tomcat and KeyManagerFactory.init also need the correct key password for each PrivateKeyEntry alias unless store and key passwords were set the same at creation time.

6. How do I verify the key password for an alias?

Run keytool -keypasswd -alias ALIAS -keystore FILE -storepass STORE -keypass GUESS -new TEMP -noprompt. If GUESS is correct the command succeeds; if wrong you get Cannot recover key from keytool as well.
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive …