Amazon Linux 2 Is Past End of Life: The AL2023 Migration in Practice
AL2 stopped getting security updates on 30 June 2026. The upgrade is not a version bump, it is a different distribution, and these are the specific pieces that break.
Amazon Linux 2 reached end of support on 30 June 2026. Instances still boot, workloads still run, and nothing about that changed on 1 July. What changed is that the next kernel or OpenSSL advisory will not arrive as a package for you.
The awkward part is that AL2023 is not AL2 with newer packages. It is built from a different upstream lineage, uses a different package manager, a different init story for several services, and a different set of defaults. Treating it as a version bump is how migrations end up half finished in a stuck Auto Scaling group.
Details below were checked against AWS documentation on 21 August 2026.
What you get for the work
AL2023 is supported for five years, which puts the next deadline in 2029, and it has the modern package versions and a FIPS certification story that AL2 does not.
The more useful difference for day to day operations is deterministic upgrades. AL2023 pins to a specific repository version at launch, so two instances launched from the same template a month apart get the same packages unless you deliberately move the version. AL2’s behavior of installing security updates at boot meant that a scaling event could introduce a package change nobody chose. If you have ever had a new instance behave differently from its siblings, that was often this.
The replacements you will actually hit
| AL2 | AL2023 |
|---|---|
yum | dnf |
amazon-linux-extras | ordinary repository packages |
dhclient | systemd-networkd |
cron | systemd timers |
rsyslog | systemd journal |
| cgroup v1 | cgroup v2 only |
lsb_release | /etc/os-release |
| Python 2.7 available | Python 3 only |
| MATE desktop | GNOME |
dnf is largely compatible at the command line, which lulls people into thinking the rest will be. It is the entries below it that break scripts.
Anything parsing lsb_release output fails outright, because the command is not installed and the system-lsb-core package does not exist. The replacement is reading /etc/os-release, which is a one line change in your provisioning scripts and a change you have to find first.
cron being replaced by systemd timers is the one that silently does nothing. A crontab file copied into an image on AL2023 does not produce an error that anyone reads, it produces a job that never runs, and you discover it when a nightly task has quietly not happened for a week. Convert those to timers deliberately and check systemctl list-timers on a real instance before you trust it.
Log shipping breaks in the same quiet way. If something on the host tails /var/log/messages, that file is not being written by rsyslog anymore. Point the shipper at the journal, or install and configure rsyslog explicitly if changing the shipper is not on the table.
The defaults that change behavior without changing your code
/tmp is now tmpfs, which means it lives in memory and does not survive a reboot. Any process writing large temporary files there is now competing for RAM, and any process that expected a file to still be there after a restart is wrong. This one shows up as an out of memory kill on a workload that never had memory problems.
cgroup v2 is the only hierarchy available. Older container runtimes and anything that reads cgroup paths directly need to be current, which is worth checking before the migration rather than during it.
cloud-init now fails closed. On AL2, an unreachable remote resource referenced from user data was ignored; on AL2023 it is a fatal error that fails the cloud-init run. That is the safer behavior and it will surface a fragile bootstrap you did not know you had, usually on the first launch into a subnet with different egress rules.
SSH host key configuration also changed, and 32 bit userspace packages are simply gone. If you are still shipping a 32 bit binary, the documented workaround is running it inside an AL2 container on top of AL2023, which is a fine answer to have and a bad answer to discover during a cutover.
The default JVM is Amazon Corretto and the AWS CLI is v2. Both are usually improvements. Both can change behavior in scripts that parse CLI output, since v2 changed several output and paging defaults from v1.
An order that does not strand you
Start with a single non production instance built from your existing automation, and let it fail. The failures are informative and they arrive in the first ten minutes: package names that no longer exist, amazon-linux-extras calls, and whatever your bootstrap fetches from a host that is not reachable.
Fix the provisioning path before touching anything that serves traffic, then bake an AMI rather than converting live instances. There is no in place upgrade from AL2 to AL2023, and pretending otherwise produces a machine in a state nobody can reproduce.
Run the two side by side behind the same load balancer for a few days if your architecture allows it. The differences that matter are not the ones in the table above; they are the ones in your own code that assumed a file, a log location, or a temporary directory that behaves differently now.
Cron jobs go last and get verified individually, because they are the class of failure that reports success right up until somebody asks where the report went.
Do this before the next advisory rather than after. The migration is a week of unglamorous work at almost any scale, and every week you wait, the gap between what your instances run and what is patched gets wider.