How to Install OpenJDK 21 on Debian 13, 12 and 11

Install OpenJDK 21 on Debian 13, 12, and 11 with Debian APT or Temurin. Covers package choice, verification, Java switching, and cleanup.

Last updatedAuthorJoshua JamesRead time8 minGuide typeDebian

Java 21 is still the target release for many Spring Boot 3.x services, Gradle builds, and application servers, but Debian does not package it the same way on every supported release. If you need to install OpenJDK 21 on Debian, the clean path depends on whether you are on Debian 13 (Trixie), Debian 12 (Bookworm), or Debian 11 (Bullseye).

Debian 13 carries openjdk-21-jdk in the default APT sources, while Debian 12 (Bookworm) and Debian 11 (Bullseye) need Eclipse Temurin from Adoptium instead. After Java 21 is in place, you can verify java and javac, switch active JDKs with update-alternatives, set JAVA_HOME, fix the common package-name error, and remove the packages cleanly later.

Install OpenJDK 21 on Debian

Two installation paths matter here. Debian 13 users can stay inside the default repositories, while Debian 12 and Debian 11 need the Temurin 21 packages from Adoptium.

MethodChannelWorks OnUpdatesBest For
Debian APTDebian packagesDebian 13APT-managed Debian updatesSimplest distro-managed OpenJDK 21 install
Eclipse Temurin APTAdoptium Linux packagesDebian 12, Debian 11APT-managed Adoptium updatesJava 21 on older supported Debian releases

Most readers should stay with Debian’s own package when they are on Debian 13. Debian 12 and Debian 11 readers should skip straight to Temurin, because openjdk-21-jdk is not packaged in their default APT sources.

Refresh APT Before Installing OpenJDK 21

Refresh APT first so Debian pulls current package metadata. Run a full system upgrade separately during your normal maintenance window rather than bundling it into the Java install.

sudo apt update

Package-management commands use sudo when they need root privileges. If your account is not in the sudoers file yet, follow the guide on how to add a user to sudoers on Debian before continuing.

Install OpenJDK 21 from Debian Repositories

Debian 13 is the only stable Debian release covered here that publishes openjdk-21-jdk in the default repositories. Use explicit OpenJDK 21 package names instead of default-jdk when you want to stay on Java 21.

Confirm that APT can already see the package before you install it:

apt-cache policy openjdk-21-jdk
openjdk-21-jdk:
  Installed: (none)
  Candidate: 21.0.11+10-1~deb13u2
  Version table:
     21.0.11+10-1~deb13u2 500
        500 http://deb.debian.org/debian trixie/main amd64 Packages
        500 http://security.debian.org/debian-security trixie-security/main amd64 Packages

Choose the package variant that matches your workload:

PackageIncludesBest For
openjdk-21-jdkCompiler, runtime, and desktop librariesGeneral development work and IDE use
openjdk-21-jdk-headlessCompiler and runtime without GUI librariesBuild servers, CI jobs, and containers
openjdk-21-jreDesktop runtime onlyRunning Java applications without compiling them
openjdk-21-jre-headlessHeadless runtime onlyServer-side Java application runtime

Install only the package you need. Most readers want the full JDK because it includes both the runtime and compiler:

sudo apt install openjdk-21-jdk -y

Use one of the smaller variants instead when you know the system only needs that role:

VariantInstall Command
Headless development kitsudo apt install openjdk-21-jdk-headless -y
Desktop runtime onlysudo apt install openjdk-21-jre -y
Headless runtime onlysudo apt install openjdk-21-jre-headless -y

Verify the active runtime with java --version after the package finishes installing:

java --version
openjdk 21.0.11 2026-04-21
OpenJDK Runtime Environment (build 21.0.11+10-1-deb13u2-Debian)
OpenJDK 64-Bit Server VM (build 21.0.11+10-1-deb13u2-Debian, mixed mode, sharing)

If you installed a JDK package rather than a JRE-only package, confirm the compiler is available too:

javac --version
javac 21.0.11

Check the active Java binary path when you need the exact installation directory:

readlink -f "$(command -v java)"
/usr/lib/jvm/java-21-openjdk-amd64/bin/java

To update Debian’s OpenJDK 21 package later without upgrading unrelated packages, run a targeted upgrade and swap in the package name you actually installed if you picked a JRE or headless variant:

sudo apt update
sudo apt install --only-upgrade openjdk-21-jdk -y

Install Eclipse Temurin 21 on Debian

Debian 12 and Debian 11 do not ship openjdk-21-jdk, so use Adoptium’s Temurin 21 packages when you need Java 21 on those releases. This path keeps updates inside APT instead of forcing a manual tarball install.

Install the packages needed to add the repository securely:

sudo apt install ca-certificates curl gpg -y

Download the Adoptium signing key as an unprivileged user, convert it to a binary keyring, and install the finished keyring into the root-owned APT keyring path:

tmp_dir="$(mktemp -d)"
curl -fsSLo "$tmp_dir/adoptium.asc" https://packages.adoptium.net/artifactory/api/gpg/key/public
gpg --dearmor --yes -o "$tmp_dir/adoptium.gpg" "$tmp_dir/adoptium.asc"
sudo install -m 0644 "$tmp_dir/adoptium.gpg" /usr/share/keyrings/adoptium.gpg
rm -rf "$tmp_dir"

The downloaded key is ASCII-armored, and gpg --dearmor converts it into the binary keyring file that APT expects under /usr/share/keyrings/. The mktemp -d directory keeps the temporary files isolated until the final sudo install step places the keyring. The -fsSLo flags tell curl to fail on HTTP errors, stay quiet, follow redirects, and save to the named file. If you use that command often outside package setup too, learn the curl command in Linux for the wider flag set.

Create the DEB822 source file after the key is in place. The guard writes the Adoptium source only on Debian 12 or Debian 11, while Debian 13 should use Debian’s own package source instead.

. /etc/os-release
codename="${VERSION_CODENAME:-}"

case "$codename" in
bookworm | bullseye)
    printf '%s\n' \
        'Types: deb' \
        'URIs: https://packages.adoptium.net/artifactory/deb' \
        "Suites: ${codename}" \
        'Components: main' \
        'Signed-By: /usr/share/keyrings/adoptium.gpg' | sudo tee /etc/apt/sources.list.d/adoptium.sources >/dev/null
    ;;
*)
    printf 'Use the Debian repository method on this release instead: %s\n' "$codename" >&2
    ;;
esac

The first line loads your Debian release details into the current shell. Debian 12 writes bookworm into the Suites: line, while Debian 11 writes bullseye. The source uses the same Adoptium repository documented upstream, but stores it as a DEB822 .sources file for easier auditing and cleanup. If the command prints the Debian repository message instead, stop this Temurin path and use the Debian 13 method.

Refresh APT after adding the new source:

sudo apt update

Relevant output includes:

Get:4 https://packages.adoptium.net/artifactory/deb bookworm InRelease [7,507 B]
Reading package lists...

Confirm that APT can see the Temurin 21 package before you install it:

apt-cache policy temurin-21-jdk
temurin-21-jdk:
  Installed: (none)
  Candidate: 21.0.11.0.0+10-1
  Version table:
     21.0.11.0.0+10-1 500
        500 https://packages.adoptium.net/artifactory/deb bookworm/main amd64 Packages
     21.0.11.0.0+10-0 500
        500 https://packages.adoptium.net/artifactory/deb bookworm/main amd64 Packages

Debian 11 shows the same package version from the bullseye suite instead of bookworm. The package name stays temurin-21-jdk on both releases.

Install the full JDK when you need Java 21 for builds, compilers, or tools like Apache Maven on Debian:

sudo apt install temurin-21-jdk -y

If you only need the runtime, swap in temurin-21-jre instead. Adoptium does not use Debian’s -headless package split for this repository, so server workloads on Docker on Debian should choose between the Temurin JDK and JRE packages.

Verify the Temurin runtime after installation:

java --version
openjdk 21.0.11 2026-04-21 LTS
OpenJDK Runtime Environment Temurin-21.0.11+10 (build 21.0.11+10-LTS)
OpenJDK 64-Bit Server VM Temurin-21.0.11+10 (build 21.0.11+10-LTS, mixed mode, sharing)

Confirm the compiler too when you installed the JDK package:

javac --version
javac 21.0.11

The active Java path confirms whether you are using Temurin or Debian’s own package:

readlink -f "$(command -v java)"
/usr/lib/jvm/temurin-21-jdk-amd64/bin/java

Temurin 21 updates through the same Adoptium repository, so a normal targeted APT upgrade keeps it current later:

sudo apt update
sudo apt install --only-upgrade temurin-21-jdk -y

Test Java 21 Compilation on Debian

After installing a JDK package from either source, compile and run a tiny class to prove that the compiler and runtime work together. Skip this check if you installed only a JRE package.

mkdir -p /tmp/java-test
cd /tmp/java-test || exit
cat > Hello.java <<'EOF'
public class Hello {
    public static void main(String[] args) {
        System.out.println("OpenJDK 21 works");
    }
}
EOF
javac Hello.java
java Hello
OpenJDK 21 works

Remove the temporary test directory after the check passes:

cd "$HOME" || exit
rm -rf /tmp/java-test

Compare Debian Default Java Versions for OpenJDK 21

Debian’s default-jdk package changes by release, which is why OpenJDK 21 is Debian-packaged on one release and an alternate vendor install on the older ones.

Debian Releasedefault-jdk Maps ToOpenJDK 21 StatusWhat It Means
Debian 13 (Trixie)OpenJDK 21.xopenjdk-21-jdk is available in the default repositoriesUse Debian APT unless you have a vendor-specific reason not to
Debian 12 (Bookworm)OpenJDK 17.xopenjdk-21-jdk is not packaged in the default APT sourcesUse Temurin 21 when a project needs Java 21
Debian 11 (Bullseye)OpenJDK 11.xopenjdk-21-jdk is not packaged in the default APT sourcesUse Temurin 21 when you need a supported Java 21 build

If you would rather stay on the distro-default branch for Debian 12, compare OpenJDK 17 on Debian. If a newer project is already moving to the next LTS line on Debian 13, compare OpenJDK 25 on Debian before you pin Java 21 out of habit.

Manage Multiple Java Versions on Debian

Debian uses update-alternatives to manage the active java and javac symlinks. That lets you keep more than one JDK installed without editing /usr/bin by hand.

Check the Active Java Runtime on Debian

List the installed runtime choices first so you can see which JDK currently owns /usr/bin/java. On a system that also has Java 25 installed, the output can look like this:

sudo update-alternatives --display java
java - auto mode
  link best version is /usr/lib/jvm/java-25-openjdk-amd64/bin/java
  link currently points to /usr/lib/jvm/java-25-openjdk-amd64/bin/java
  link java is /usr/bin/java
  slave java.1.gz is /usr/share/man/man1/java.1.gz
/usr/lib/jvm/java-21-openjdk-amd64/bin/java - priority 2111
  slave java.1.gz: /usr/lib/jvm/java-21-openjdk-amd64/man/man1/java.1.gz
/usr/lib/jvm/java-25-openjdk-amd64/bin/java - priority 2511

If you want to switch the active runtime interactively, run sudo update-alternatives --config java and choose the Java 21 entry.

Check the Active Java Compiler on Debian

Keep the compiler aligned with the runtime so your build tools and bytecode targets stay on the same Java major version. On a system that also has Java 25 installed, the compiler alternatives can look like this:

sudo update-alternatives --display javac
javac - auto mode
  link best version is /usr/lib/jvm/java-25-openjdk-amd64/bin/javac
  link currently points to /usr/lib/jvm/java-25-openjdk-amd64/bin/javac
  link javac is /usr/bin/javac
  slave javac.1.gz is /usr/share/man/man1/javac.1.gz
/usr/lib/jvm/java-21-openjdk-amd64/bin/javac - priority 2111
  slave javac.1.gz: /usr/lib/jvm/java-21-openjdk-amd64/man/man1/javac.1.gz
/usr/lib/jvm/java-25-openjdk-amd64/bin/javac - priority 2511

Use sudo update-alternatives --config javac when you need to move the compiler back to Java 21 after installing another JDK.

Find the Active JAVA_HOME Path on Debian

Check the active Java binary first, then use the parent directory as JAVA_HOME. With Debian’s own OpenJDK 21 package selected, the active path looks like this:

readlink -f "$(command -v java)"
/usr/lib/jvm/java-21-openjdk-amd64/bin/java

With Debian’s own OpenJDK 21 package selected, JAVA_HOME is /usr/lib/jvm/java-21-openjdk-amd64. With Temurin 21 selected, it is /usr/lib/jvm/temurin-21-jdk-amd64.

The safest way to capture the actual JAVA_HOME directory is to strip the trailing /bin/java from the active binary path. With Temurin 21 active, the command returns:

dirname "$(dirname "$(readlink -f "$(command -v java)")")"
/usr/lib/jvm/temurin-21-jdk-amd64

If a build tool needs the variable exported later, add the path that command prints to your shell profile as export JAVA_HOME=/path/to/jdk. Replace any existing JAVA_HOME line instead of appending duplicates.

Troubleshoot OpenJDK 21 on Debian

Most OpenJDK 21 problems on Debian come from package-name assumptions or from another JDK staying active after the install. These checks narrow the issue quickly.

Fix Unable to Locate OpenJDK 21 Packages on Debian

Debian 12 and Debian 11 do not ship Debian OpenJDK 21 package names such as openjdk-21-jdk, openjdk-21-jre, or openjdk-21-jre-headless, so APT can return this error even after a normal apt update:

Reading package lists...
Building dependency tree...
Reading state information...
E: Unable to locate package openjdk-21-jdk

Confirm the package source before changing anything else:

apt-cache policy openjdk-21-jdk openjdk-21-jre openjdk-21-jre-headless

On Debian 12 or Debian 11, no package stanza or Candidate: (none) means the default repositories do not provide those Debian OpenJDK 21 package names; add the Adoptium repository and install temurin-21-jdk or temurin-21-jre instead. Do not add a -headless suffix to Temurin package names, because Adoptium does not publish that split in this repository. On Debian 13, rerun sudo apt update and check that the default Debian repositories are enabled before retrying the Debian package name.

Fix the Wrong Active Java Version on Debian

If java --version still reports Java 17 or Java 25 after you install Java 21, switch both the runtime and compiler back to the Java 21 entries:

sudo update-alternatives --config java
sudo update-alternatives --config javac
java --version
javac --version
openjdk 21.0.11 2026-04-21
OpenJDK Runtime Environment (build 21.0.11+10-1-deb13u2-Debian)
OpenJDK 64-Bit Server VM (build 21.0.11+10-1-deb13u2-Debian, mixed mode, sharing)

javac 21.0.11

Remove OpenJDK 21 or Temurin 21 on Debian

Remove only the package set you actually installed. Debian’s own OpenJDK packages and Adoptium’s Temurin packages use different package names and cleanup steps.

Remove Debian OpenJDK 21 Packages on Debian

Use this package cleanup path when you installed Java 21 from Debian 13’s own repositories. If you only installed one package variant, remove that package name instead of the full list. Keep apt autoremove as a separate review step so APT does not remove unrelated packages that were already marked automatic.

sudo apt remove openjdk-21-jdk openjdk-21-jdk-headless openjdk-21-jre openjdk-21-jre-headless

Verify that the selected package is no longer installed:

dpkg-query -W -f='${db:Status-Abbrev}\n' openjdk-21-jdk 2>/dev/null | grep -q '^ii' && echo openjdk-21-jdk still installed || echo openjdk-21-jdk not installed
openjdk-21-jdk not installed

Remove Temurin 21 and the Adoptium Repository on Debian

Use the Temurin cleanup path on Debian 12 or Debian 11 after an Adoptium install. Remove the Java package first, then delete the repository source and key only when no other Temurin package on the system still needs that source.

sudo apt remove temurin-21-jdk temurin-21-jre

Check whether any Temurin packages remain before removing the shared Adoptium source and CA helper package:

remaining_temurin="$(dpkg-query -W -f='${binary:Package} ${db:Status-Abbrev}\n' 'temurin-*' 2>/dev/null | grep '^temurin-.* ii' || true)"

if [ -n "$remaining_temurin" ]; then
    printf '%s\n' "$remaining_temurin"
    echo "Temurin packages remain; keep the Adoptium source"
else
    sudo apt remove adoptium-ca-certificates
fi

If no Temurin packages remain, remove the source file, remove the keyring only if no remaining source references it, then refresh APT so Debian drops the cached repo metadata:

sudo rm -f /etc/apt/sources.list.d/adoptium.sources
if sudo grep -R --include='*.sources' --include='*.list' -q '/usr/share/keyrings/adoptium.gpg' /etc/apt/sources.list /etc/apt/sources.list.d 2>/dev/null; then
    echo "Adoptium keyring is still referenced by another source file"
else
    sudo rm -f /usr/share/keyrings/adoptium.gpg
fi
sudo apt update

Verify that no Temurin package or Adoptium CA helper remains after full cleanup:

dpkg-query -W -f='${binary:Package} ${db:Status-Abbrev}\n' 'temurin-*' adoptium-ca-certificates 2>/dev/null | grep ' ii' || echo "No Temurin packages or Adoptium CA helper remain"
No Temurin packages or Adoptium CA helper remain

Confirm that the repository files are gone too:

test ! -f /etc/apt/sources.list.d/adoptium.sources && test ! -f /usr/share/keyrings/adoptium.gpg && echo Adoptium repo files removed
Adoptium repo files removed

At that point, apt-cache policy temurin-21-jdk returns no output because Debian no longer sees the package from an active Adoptium source.

Conclusion

OpenJDK 21 is running on Debian once you match the package source to your release. Debian APT keeps Trixie simple, while Temurin covers Bookworm and Bullseye when a Spring Boot, Gradle, or application-server stack still needs Java 21. From there, the next decision is whether your projects stay on the Java 21 LTS line or move forward to a newer branch later.

Share this guide

Help another Linux user troubleshoot faster

Share this guide with someone troubleshooting Linux systems or saving it for later.

Follow LinuxCapable

Want more LinuxCapable guides in Google?

Add LinuxCapable as a preferred source so Google can show our tutorials more often in Top Stories and mark them as preferred in AI Mode and AI Overviews when relevant.

Add LinuxCapable as a preferred source on Google
Search LinuxCapable

Need another guide?

Search LinuxCapable for package installs, commands, troubleshooting, and follow-up guides related to what you just read.

Found this guide useful?

Support LinuxCapable to keep tutorials free and up to date.

Buy me a coffeeBuy me a coffee
Before commenting, please review our Comments Policy.
Formatting tips for your comment

You can use basic HTML to format your comment. Useful tags currently allowed in published comments:

You type Result
<code>command</code> command
<strong>bold</strong> bold
<em>italic</em> italic
<a href="https://example.com">link</a> link
<blockquote>quote</blockquote> quote block

Add to the discussion

Questions, fixes, command output, and version notes help keep this guide current.

Verify before posting: