Upgrade PHP 8.3 to 8.4 on Rocky Linux, RHEL, AlmaLinux, and Oracle Linux

Replace native PHP 8.3 packages with php8.4-* RPMs on EL 10, back up configuration, check application compatibility, migrate PHP-FPM settings, verify web applications, troubleshoot failures, and roll back if required.

Published

Updated

Read time 14 min read

Reviewed byDeepak Prasad

Upgrade PHP 8.3 to PHP 8.4 on Enterprise Linux banner with PHP version arrows and terminal motif
Tested on Rocky Linux 10.2 (Red Quartz)
Package php 8.3.31
php 8.4.21
php 8.3.31
Applies to RHEL, Rocky Linux, AlmaLinux, Oracle Linux, CentOS Stream, Fedora
Privilege sudo or root
Scope Upgrade PHP 8.3 to 8.4 on Rocky Linux, RHEL, AlmaLinux, and Oracle Linux, including pre-checks, migration steps, and post-upgrade verification.
Related guides Add Linux To Windows Ad Domain Realm
Boom Boot Linux Lvm Snapshot Rhel 8 Linux
Boot In Single User Mode Rhel Centos 8 Linux
Boot Rescue Mode Iso Rhel Centos 7
Boot With Old Kernel Version Rhel 8 Grubby

If php -v reports PHP 8.3 on Enterprise Linux 10, the supported native path is package replacement—not installing PHP 8.4 beside the existing major release. Inventory installed php-* RPMs, check application compatibility, back up configuration, remove PHP 8.3, install matching php8.4-* packages, merge settings, and verify PHP-FPM and your web application.

This guide covers Rocky Linux, RHEL, AlmaLinux, Oracle Linux, and CentOS Stream when both versions use native AppStream packaging. For a host with no PHP installed, use install PHP 8.4 on Enterprise Linux instead.

IMPORTANT
Review every DNF removal transaction before you confirm it. Do not use dnf install php8.4 --allowerasing as the default upgrade shortcut, and do not use dnf remove 'php*' blindly—a broad glob can match unintended packages once PHP 8.4 RPMs are present.
NOTE
Native php8.4-* packages are available in RHEL 10.2 and compatible Rocky Linux, AlmaLinux, and Oracle Linux releases. On CentOS Stream 10, confirm availability with dnf info php8.4 before you schedule the upgrade.

Prerequisites

  • RHEL, Rocky Linux, AlmaLinux, or Oracle Linux 10.2+ with PHP 8.3 installed from unprefixed php-* AppStream packages, or CentOS Stream 10 where dnf info php8.4 confirms the target package set.
  • sudo command or root access.
  • A maintenance window to stop PHP-FPM and the web server with systemctl command.
  • Application, database, and configuration backups—and a tested rollback plan.
  • A staging copy of the application when you can test PHP 8.4 compatibility before production.

Package operations in this guide use dnf command.


Check whether the system can upgrade to PHP 8.4

Confirm the operating system and that PHP 8.4 packages exist in repository metadata before you touch PHP 8.3.

Identify the distribution:

bash
cat /etc/os-release

Sample output:

output
NAME="Rocky Linux"
VERSION="10.2 (Red Quartz)"
VERSION_ID="10.2"
PRETTY_NAME="Rocky Linux 10.2 (Red Quartz)"

On RHEL, Rocky Linux, AlmaLinux, and Oracle Linux, VERSION_ID should be 10.2 or newer for the native php8.4-* set. On CentOS Stream 10, use package metadata rather than a downstream 10.2 point-release check.

Confirm the current PHP major version:

bash
php -v

Sample output on PHP 8.3:

output
PHP 8.3.31 (cli) (built: May  5 2026 13:35:55) (NTS gcc x86_64)
Zend Engine v4.3.31, Copyright (c) Zend Technologies
    with Zend OPcache v8.3.31, Copyright (c), by Zend Technologies

Exact patch and release strings vary by distribution update date. Confirm that the major version changes from PHP 8.3 to PHP 8.4 rather than requiring the same patch numbers shown here.

If php -v already reports PHP 8.4, you are past the package-replacement step—verify extensions and application behavior instead. If php is not installed, this guide does not apply—install PHP 8.4 on a fresh host first.

Check that PHP 8.4 is available in AppStream:

bash
dnf info php8.4

Sample output:

output
Available Packages
Name         : php8.4
Version      : 8.4.21
Release      : 1.el10_2
Repository   : appstream
Summary      : PHP scripting language for creating dynamic web sites

If php8.4 is missing, refresh enabled repository metadata with sudo dnf makecache --refresh, then run dnf info php8.4 again.

Identify how PHP is deployed on the host:

bash
systemctl status php-fpm

Sample output when FPM is running:

output
● php-fpm.service - The PHP FastCGI Process Manager
     Active: active (running)

Check whether Apache or Nginx is in use:

bash
systemctl is-active httpd nginx

On the tested host, httpd was active and nginx was inactive. Stop only the services that are actually running before package removal.


Inventory PHP 8.3 packages and extensions

Create the backup directory first, then save every package and extension list you need for rollback:

bash
sudo mkdir -p /root/php83-upgrade

List installed PHP packages through DNF and save the output:

bash
dnf list --installed 'php*' | sudo tee /root/php83-upgrade/dnf-packages.txt

Sample output:

output
php.x86_64                           8.3.31-1.el10_2
php-cli.x86_64                       8.3.31-1.el10_2
php-fpm.x86_64                       8.3.31-1.el10_2
php-mysqlnd.x86_64                   8.3.31-1.el10_2
...

List the same packages through rpm command and save the sorted list:

bash
rpm -qa 'php*' | sort | sudo tee /root/php83-upgrade/rpm-packages.txt

Sample output:

output
php-8.3.31-1.el10_2.x86_64
php-cli-8.3.31-1.el10_2.x86_64
php-common-8.3.31-1.el10_2.x86_64
php-fpm-8.3.31-1.el10_2.x86_64
php-mysqlnd-8.3.31-1.el10_2.x86_64
...

PHP 8.3 uses unprefixed names (php, php-fpm, php-mysqlnd). PHP 8.4 uses the php8.4-* prefix.

Save loaded extensions:

bash
php -m | sudo tee /root/php83-upgrade/php83-modules.txt

Record the configuration files PHP actually loads:

bash
php --ini

Sample output:

output
Configuration File (php.ini) Path: /etc
Loaded Configuration File:         /etc/php.ini
Scan for additional .ini files in: /etc/php.d

Map each installed PHP 8.3 package to its PHP 8.4 replacement. Verify every target with dnf info php8.4-<name> or dnf list available 'php8.4-*' before you schedule removal—not every PHP 8.3 extension has an identical PHP 8.4 package name.

PHP 8.3 package PHP 8.4 replacement
php php8.4
php-cli php8.4-cli
php-common php8.4-common
php-fpm php8.4-fpm
php-mysqlnd php8.4-mysqlnd
php-mbstring php8.4-mbstring
php-xml php8.4-xml
php-gd php8.4-gd
php-intl php8.4-intl
php-pgsql php8.4-pgsql
php-ldap php8.4-ldap

Hosts with additional packages such as php-soap, php-bcmath, php-process, or php-pecl-* must map and verify each one before removal.


Check application compatibility with PHP 8.4

Package replacement upgrades the PHP runtime—it does not upgrade your application code. Review compatibility before you remove PHP 8.3.

Check these areas on a staging copy when possible:

Run these commands from the application directory when Composer is installed and the project contains composer.json.

Before upgrading, validate the lock file and identify packages that block PHP 8.4:

bash
composer validate
bash
composer prohibits php 8.4

The prohibits command (alias: composer why-not php 8.4) reports dependencies that forbid the target PHP version. It does not use the currently running PHP 8.3 runtime the way check-platform-reqs does.

Optionally review available dependency updates:

bash
composer outdated

That command lists newer package releases—it is not itself a PHP 8.4 compatibility test.

The full language migration belongs in the PHP 8.3 to 8.4 migration guide. This article covers Enterprise Linux package replacement only.


Back up PHP and web-server configuration

Back up the files your running stack actually uses—not only php.ini.

Archive core PHP configuration into /root/php83-upgrade/:

bash
sudo cp -a /etc/php.ini /etc/php.d /root/php83-upgrade/

When PHP-FPM is installed, back up the FPM configuration as well:

bash
sudo cp -a /etc/php-fpm.conf /etc/php-fpm.d /root/php83-upgrade/

Back up only the web server this host uses.

Apache host:

bash
sudo cp -a /etc/httpd /root/php83-upgrade/httpd.bak

Nginx host:

bash
sudo cp -a /etc/nginx /root/php83-upgrade/nginx.bak

Record runtime paths before services stop:

bash
php --ini

Save the effective PHP-FPM configuration before package replacement:

bash
sudo php-fpm -tt 2>&1 | sudo tee /root/php83-upgrade/php-fpm-effective.txt

Sample output:

output
[22-Jul-2026 07:30:15] NOTICE: [global]
[22-Jul-2026 07:30:15] NOTICE: 	pid = /run/php-fpm/php-fpm.pid
[22-Jul-2026 07:30:15] NOTICE: 	error_log = /var/log/php-fpm/error.log

The command should exit successfully without an ERROR line. The saved file records the effective global and pool settings before package replacement.

Capture the systemd unit definition:

bash
systemctl cat php-fpm | sudo tee /root/php83-upgrade/php-fpm.service.txt > /dev/null

Record the pre-upgrade enablement state for the stack you use.

Apache host:

bash
systemctl is-enabled php-fpm httpd 2>&1 | sudo tee /root/php83-upgrade/apache-service-state.txt

Nginx host:

bash
systemctl is-enabled php-fpm nginx 2>&1 | sudo tee /root/php83-upgrade/nginx-service-state.txt

Also back up application files, Composer lock files, environment files, and databases when the upgrade may change application data. Do not plan to restore the entire PHP 8.3 configuration tree blindly over PHP 8.4.


Replace PHP 8.3 packages with PHP 8.4

Stop PHP-FPM and the web server you use.

For Apache:

bash
sudo systemctl stop php-fpm httpd

For Nginx:

bash
sudo systemctl stop php-fpm nginx

Preview removal of the PHP 8.3 packages from your inventory. Adjust the list to match /root/php83-upgrade/dnf-packages.txt or dnf list --installed 'php*'. A host with packages such as php-ldap, php-pgsql, php-soap, php-bcmath, php-process, or php-pecl-* must include every installed PHP 8.3 RPM in the removal list—leftover extension packages can block the PHP 8.4 install.

bash
sudo dnf remove --assumeno php php-cli php-common php-fpm \
  php-gd php-intl php-mbstring php-mysqlnd php-opcache \
  php-pdo php-xml

Sample transaction summary:

output
Transaction Summary
================================================================================
Remove  47 Packages

Freed space: 72 M
Operation aborted.

Read the full package list. DNF may propose removing httpd, font packages, or other dependencies installed only because PHP was present.

Remove the PHP 8.3 package set after you review the transaction:

bash
sudo dnf remove php php-cli php-common php-fpm php-gd php-intl php-mbstring php-mysqlnd php-opcache php-pdo php-xml

Install PHP 8.4 and the extensions you mapped earlier. The example below matches the tested inventory—change it to fit your host:

bash
sudo dnf install php8.4 php8.4-fpm php8.4-mysqlnd php8.4-mbstring php8.4-xml php8.4-gd php8.4-intl php8.4-opcache

Do not copy that command unchanged. Every package name must come from /root/php83-upgrade/dnf-packages.txt and dnf list available 'php8.4-*' results.


Review and migrate PHP configuration

Compare the backed-up PHP 8.3 files with the newly installed PHP 8.4 defaults before you restart services.

Review the main CLI configuration:

bash
php --ini

Inspect effective runtime values:

bash
php -i

Validate PHP-FPM syntax and dump the active configuration:

bash
php-fpm -tt

Compare individual files with diff when you need to merge a setting:

bash
diff -u /root/php83-upgrade/php.ini /etc/php.ini

Transfer only the settings you still need:

  • memory_limit, upload_max_filesize, and post_max_size
  • Time zone and error-reporting levels
  • Opcache settings under /etc/php.d/
  • Session storage paths
  • PHP-FPM pool user, group, listen, and process-manager values

Confirm the FPM socket or listener matches your web-server integration. Match the exact listen = assignment:

bash
grep -E '^[[:space:]]*listen[[:space:]]*=' /etc/php-fpm.d/www.conf

Sample output:

output
listen = /run/php-fpm/www.sock

Check for RPM-preserved configuration files after package changes:

bash
sudo find /etc -type f \( -name '*.rpmnew' -o -name '*.rpmsave' \) -path '*php*'

RPM may leave modified files as .rpmsave or install updated defaults as .rpmnew. Review those paths before you delete anything.


Start PHP 8.4 and verify the upgrade

Restore the service enablement state recorded before the upgrade. If PHP-FPM and the web server were enabled in /root/php83-upgrade/apache-service-state.txt or nginx-service-state.txt, enable and start them again. systemctl start brings a unit up for the current boot only; systemctl enable creates the boot-time symlinks Red Hat documents separately from startup.

When both services were enabled before package replacement:

Apache host:

bash
sudo systemctl enable --now php-fpm httpd

Nginx host:

bash
sudo systemctl enable --now php-fpm nginx

When a service was intentionally disabled but not masked, use sudo systemctl start <unit> and leave its boot enablement unchanged. When it was masked before the upgrade, leave it stopped and masked unless you intentionally want to change that policy. A masked unit must be unmasked before it can be started.

Verify the CLI:

bash
php -v

Sample output:

output
PHP 8.4.21 (cli) (built: May  5 2026 16:34:12) (NTS gcc x86_64)
Zend Engine v4.4.21, Copyright (c) Zend Technologies
    with Zend OPcache v8.4.21, Copyright (c), by Zend Technologies

Exact patch and release strings vary by distribution update date. Confirm PHP 8.4.x—not a specific patch number shown here.

Confirm extensions:

bash
php -m

When the application uses Composer, verify platform requirements against the running PHP 8.4 runtime from the project directory:

bash
composer check-platform-reqs

The command checks the real PHP 8.4 runtime and loaded extensions against the platform requirements of the installed Composer packages. It ignores any simulated config.platform value.

Validate FPM and the unit:

bash
php-fpm -tt
bash
systemctl status php-fpm

Test the web stack with a temporary script. Run only the block for the web server used by this host.

Apache verification—document root /var/www/html:

bash
echo '<?php echo "PHP " . PHP_VERSION . " via " . php_sapi_name(); ?>' | sudo tee /var/www/html/test.php

Request the page with curl command:

bash
curl -s http://127.0.0.1/test.php

Sample output:

output
PHP 8.4.21 via fpm-fcgi
bash
sudo rm /var/www/html/test.php

Nginx verification—document root /usr/share/nginx/html:

bash
echo '<?php echo "PHP " . PHP_VERSION . " via " . php_sapi_name(); ?>' | sudo tee /usr/share/nginx/html/test.php
bash
curl -s http://127.0.0.1/test.php

Sample output:

output
PHP 8.4.21 via fpm-fcgi
bash
sudo rm /usr/share/nginx/html/test.php

After package verification, test application behavior:

  • Database connectivity and ORM queries
  • File uploads and downloads
  • Sessions and authentication
  • Scheduled cron jobs and queue workers
  • Composer commands in the project directory
  • Administration pages and plugin modules
  • PHP-FPM, web-server, and application error logs

Compare the current enablement state with the state saved before the upgrade.

Apache host:

bash
systemctl is-enabled php-fpm httpd
bash
cat /root/php83-upgrade/apache-service-state.txt

Nginx host:

bash
systemctl is-enabled php-fpm nginx
bash
cat /root/php83-upgrade/nginx-service-state.txt

Compare each unit’s current enablement state with its saved pre-upgrade state. The values should match unless you intentionally changed the service policy; possible results include enabled, disabled, or masked.

Red Hat distinguishes disabling from masking: a disabled service can still be started manually, while a masked service cannot start until it is unmasked.


Troubleshoot failed PHP 8.4 upgrades

Symptom Main check
php still reports PHP 8.3 rpm -qa 'php*', which php; finish removing unprefixed PHP 8.3 RPMs
DNF reports package conflicts Remove remaining PHP 8.3 packages before installing php8.4-*
PHP extension is missing Compare /root/php83-upgrade/php83-modules.txt with php -m; install the matching php8.4-* package
PHP-FPM fails to start php-fpm -tt and sudo journalctl -u php-fpm
Apache or Nginx returns 502 Bad Gateway Confirm php-fpm is active and the socket matches /run/php-fpm/www.sock
Application returns HTTP 500 Inspect PHP-FPM, web-server, and application logs
Old PHP settings are ignored php --ini, php-fpm -tt, and .rpmnew / .rpmsave files under /etc
Composer reports platform errors Update dependencies or adjust config.platform.php after confirming runtime compatibility
Scheduled scripts fail Confirm cron uses /usr/bin/php and required extensions are installed
SELinux blocks application access Inspect /var/log/audit/audit.log before changing policy

Useful inspection commands—see view logs with journalctl for unit filters and follow mode:

bash
sudo journalctl -u php-fpm
bash
sudo journalctl -u httpd
bash
sudo journalctl -u nginx
bash
rpm -qa 'php*' | sort

Roll back from PHP 8.4 to PHP 8.3

Roll back only when you have backups and accept that application or database changes made after the PHP 8.4 upgrade may need their own reversal.

Before you remove PHP 8.4, confirm that the PHP 8.3 packages from /root/php83-upgrade/dnf-packages.txt are still available in repository metadata:

bash
dnf info php php-cli php-common php-fpm

Check every extension package from the saved inventory as well—for example dnf info php-mysqlnd php-xml php-gd.

Stop PHP-FPM and the web server you use.

Apache host:

bash
sudo systemctl stop php-fpm httpd

Nginx host:

bash
sudo systemctl stop php-fpm nginx

Record the installed PHP 8.4 packages:

bash
dnf list --installed 'php8.4-*'

Preview removal of the PHP 8.4 family:

bash
sudo dnf remove --assumeno 'php8.4*'

Sample transaction summary:

output
Transaction Summary
================================================================================
Remove  47 Packages

Freed space: 75 M
Operation aborted.

Remove PHP 8.4 after you review the list:

bash
sudo dnf remove 'php8.4*'

Reinstall the PHP 8.3 packages listed in /root/php83-upgrade/dnf-packages.txt:

bash
sudo dnf install php php-cli php-common php-fpm php-mysqlnd php-mbstring php-xml php-gd php-intl php-opcache

Restore compatible PHP 8.3 configuration from /root/php83-upgrade/—merge only the settings that still apply.

Restore service enablement the same way as after the PHP 8.4 install. When PHP-FPM and the web server were enabled before the upgrade, enable and start them again.

Apache host:

bash
sudo systemctl enable --now php-fpm httpd
bash
systemctl is-active php-fpm httpd

Nginx host:

bash
sudo systemctl enable --now php-fpm nginx
bash
systemctl is-active php-fpm nginx

When a service was intentionally disabled but not masked, use sudo systemctl start <unit> and leave its boot enablement unchanged. When it was masked before the upgrade, leave it stopped and masked unless you intentionally want to change that policy. A masked unit must be unmasked before it can be started.

Only when you deliberately change that policy—not as part of the normal rollback—unmask first:

bash
sudo systemctl unmask php-fpm
sudo systemctl start php-fpm

Compare enablement against the saved state file when you need to confirm boot persistence.

Apache host:

bash
systemctl is-enabled php-fpm httpd
bash
cat /root/php83-upgrade/apache-service-state.txt

Nginx host:

bash
systemctl is-enabled php-fpm nginx
bash
cat /root/php83-upgrade/nginx-service-state.txt

Compare each unit individually. Restore its original enabled, disabled, or masked state unless you deliberately want to change the boot policy.

Verify the rollback:

bash
php -v

Sample output:

output
PHP 8.3.31 (cli) (built: May  5 2026 13:35:55) (NTS gcc x86_64)
Zend Engine v4.3.31, Copyright (c) Zend Technologies
    with Zend OPcache v8.3.31, Copyright (c), by Zend Technologies

Exact patch and release strings vary by distribution update date. Confirm the major version returned to PHP 8.3.x rather than requiring the same patch numbers shown here.

On the tested host, removing php8.4-* and reinstalling the PHP 8.3 package set returned CLI 8.3.31.


References


Summary

Upgrading from PHP 8.3 to PHP 8.4 on Enterprise Linux is native package replacement: save package inventories under /root/php83-upgrade/, check application compatibility, back up PHP and web-server configuration, stop services, review DNF removal output, install matching php8.4-* packages, merge settings carefully, and verify CLI, PHP-FPM, Composer platform requirements, and the application. Roll back by removing php8.4-*, reinstalling PHP 8.3 from the saved inventory, and restoring compatible configuration.


Frequently Asked Questions

1. Can PHP 8.3 and PHP 8.4 run together on Rocky Linux 10 with native packages?

No. Native php8.4-* RPMs still own /usr/bin/php, /etc/php.ini, and php-fpm.service. Replace PHP 8.3 with PHP 8.4, or run each version in its own container or VM.

2. Why is my PHP extension missing after upgrading to PHP 8.4?

Extensions are separate RPMs. PHP 8.3 used names like php-mysqlnd; PHP 8.4 uses php8.4-mysqlnd. Compare your pre-upgrade php -m output with the new list and install each matching php8.4-* package.

3. Should I copy /etc/php.d/ from PHP 8.3 to PHP 8.4?

No. Copy individual settings from your backup into the new php.ini and pool files. Blindly copying the whole php.d tree can leave drop-ins that reference extensions you have not installed yet.

4. Can I use dnf install php8.4 --allowerasing to upgrade?

Not as the default shortcut. --allowerasing can remove extensions or dependencies without installing matching php8.4-* replacements. Inventory packages, review each DNF transaction, and install the required php8.4-* set explicitly.

5. What if dnf remove wants to erase httpd or nginx?

Review the full removal transaction. If the web server was installed only as a PHP dependency, DNF may propose removing it. Reinstall the web server after PHP 8.4 is in place if you still need it.

6. How do I roll back from PHP 8.4 to PHP 8.3?

Stop php-fpm and the web server, remove php8.4-* packages, reinstall the PHP 8.3 packages from your inventory, restore compatible configuration from backup, and restart services. Application or database changes made after the upgrade may need their own rollback.

7. Where is the fresh PHP 8.4 install guide?

Use the install PHP 8.4 on Enterprise Linux article for a new host without PHP 8.3 already installed.
Omer Cakmak

Linux Administrator

Highly skilled at managing Debian, Ubuntu, CentOS, Oracle Linux, and Red Hat servers. Proficient in bash scripting, Ansible, and AWX central server management, he handles server operations on …