Upgrade PHP on a Debian LAMP Stack
One of the advantages of building a LAMP stack from a bare Debian OS image is that each component is managed independently through APT. When a new PHP version is released, an in-place upgrade involves installing the new PHP packages alongside the existing version, updating the Apache configuration, and removing the old packages after verification. No instance replacement, no content migration, no waiting for a managed hosting provider to make the version available.
This guide covers upgrading PHP on a Debian LAMP stack running Apache with PHP-FPM. It also covers updating Apache and MariaDB through APT as part of the same maintenance pass. If the server was built following Install and Harden a Debian LAMP Stack on Amazon Lightsail, the steps here apply directly to that configuration.
The examples throughout use PHP 8.4 as the installed version and PHP 8.5 as the target. Substitute the appropriate version numbers wherever they appear in commands and file paths. For a new upgrade, use the latest PHP branch supported by the application and available for the Debian release. The package and Apache configuration steps are generally the same for other supported PHP version upgrades, but always review the migration guide for the target PHP release for version-specific changes.
NOTE: This guide covers upgrading between PHP releases (for example, PHP 8.4 to PHP 8.5) while remaining on the same Debian release. A major Debian OS upgrade, such as from Debian 12 to Debian 13, involves significantly more risk and is better handled by provisioning a fresh instance and following the install guide rather than upgrading in place. The same applies to any upgrade where the underlying OS default PHP version changes or where significant package conflicts are expected.
When to Upgrade PHP
Each PHP version follows a three-stage lifecycle: active support, security-only patches, and end of life. Monitor PHP version support timelines as part of routine maintenance.
- Active support means the version receives both bug fixes and security patches. This is the target stage.
- Security fixes only means active bug fix support has ended; the version still receives critical security patches but no other fixes.
- End of life means the version receives nothing, and running it on a public-facing server is a security risk.
The upgrade should be planned before the current version reaches end of life, preferably before it enters security-only support. Waiting until end of life compresses the upgrade window and increases the risk of running unpatched code on a production server.
Before upgrading, confirm the target version has sufficient ecosystem support for the application. WordPress core typically adopts new PHP releases quickly, while plugins may take longer to declare compatibility. Check the WordPress hosting requirements and test the plugin stack against the target version before upgrading a production server.
Before Upgrading
Check for Plugin Compatibility Issues
Each new PHP version enforces stricter handling of some patterns that earlier versions silently permitted. Before upgrading, check whether the installed plugins and themes have known compatibility issues with the target PHP version. If desired, a compatibility scanner can help identify potential issues before upgrading.
For non-WordPress PHP applications, install the new PHP version alongside the existing version and test the application against the new PHP runtime before switching production traffic to it. A staging environment is preferable for this testing. Reviewing the PHP migration guide and application logs can help identify deprecated or incompatible code before the production switch.
Take a Snapshot
Take a snapshot of the instance before proceeding. Following these steps reduces upgrade risk, but a snapshot provides a recovery point if something unexpected occurs.
In Lightsail, click the instance name, click the Snapshots tab, and click Create snapshot. Verify that the snapshot completed successfully before proceeding.
On a different hosting provider, use whatever snapshot or backup mechanism is available before proceeding.
Update Apache and MariaDB
Before upgrading PHP, update Apache and MariaDB through APT. This ensures the server is running the latest security patches for both components before adding a new PHP version on top.
The command below updates every installed package, including PHP 8.4, to the newest version available within its current branch. It does not upgrade PHP 8.4 to PHP 8.5. The newer version is installed separately in a later step, and PHP 8.4 remains installed until it is removed at the end of this guide.
sudo apt update && sudo apt upgrade -y
Review the output for any notices about held packages or configuration file prompts. If APT prompts about a configuration file, review the differences and retain the existing version if it contains intentional local customizations. Do not automatically replace a customized production configuration with the package maintainer’s version.
NOTE: This guide uses
apt upgraderather thanapt full-upgrade.apt upgradeis more conservative for routine maintenance because it does not remove installed packages to complete an upgrade. If an update requires removing an installed package, APT holds that package back.apt full-upgradeallows APT to make package removals and dependency changes when necessary to complete the upgrade.
Restart Apache and MariaDB if either was updated:
sudo systemctl restart mariadb
sudo apache2ctl configtest
sudo systemctl restart apache2
Verify both services are running:
sudo systemctl status apache2
sudo systemctl status mariadb
Add the Sury PHP Repository
Debian 13 does not include PHP 8.5 in its default repositories. The Sury repository is a well-established source for PHP versions that are not available in Debian’s default repositories.
Install the required supporting packages first:
sudo apt install -y ca-certificates curl lsb-release
Download and install the Sury keyring package. This places the repository signing key in /usr/share/keyrings/ using the current recommended approach rather than the deprecated apt-key workflow:
sudo curl -sSLo /tmp/debsuryorg-archive-keyring.deb https://packages.sury.org/debsuryorg-archive-keyring.deb
sudo dpkg -i /tmp/debsuryorg-archive-keyring.deb
Add the Sury PHP repository to APT’s source list:
sudo sh -c 'echo "deb [signed-by=/usr/share/keyrings/debsuryorg-archive-keyring.gpg] https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/php.list'
Update the package index to make APT aware of the new repository:
sudo apt update && sudo apt upgrade -y
Adding the repository does not install or switch to PHP 8.5.
Install PHP 8.5
Install PHP 8.5 with PHP-FPM and the same extensions used in the install guide:
sudo apt install -y php8.5 php8.5-{common,fpm,mysql,curl,igbinary,imagick,intl,mbstring,xml,zip}
After installation, confirm the PHP 8.5 CLI is installed and reports the expected version:
php8.5 -v
Configure PHP 8.5 for Production
The PHP 8.5 configuration file at /etc/php/8.5/fpm/php.ini contains the default values used by a new PHP installation. Apply the same production settings used in the original LAMP installation. These commands modify the existing directives in the default php.ini:
sudo sed -i 's/^memory_limit = .*/memory_limit = 256M/' /etc/php/8.5/fpm/php.ini
sudo sed -i 's/^upload_max_filesize = .*/upload_max_filesize = 64M/' /etc/php/8.5/fpm/php.ini
sudo sed -i 's/^post_max_size = .*/post_max_size = 72M/' /etc/php/8.5/fpm/php.ini
sudo sed -i 's/^max_execution_time = .*/max_execution_time = 120/' /etc/php/8.5/fpm/php.ini
sudo sed -i 's/^expose_php = .*/expose_php = Off/' /etc/php/8.5/fpm/php.ini
If a disable_functions directive was applied to the PHP 8.4 installation, apply it to PHP 8.5 as well:
sudo sed -i 's/^disable_functions =.*/disable_functions = exec,passthru,shell_exec,system,proc_open,popen/' /etc/php/8.5/fpm/php.ini
If any other customizations were made to /etc/php/8.4/fpm/php.ini, compare both files before continuing:
diff /etc/php/8.4/fpm/php.ini /etc/php/8.5/fpm/php.ini
Review the diff output and port any intentional customizations from the 8.4 file to the 8.5 file. Ignore differences in version-specific default values; focus only on lines that were changed deliberately.
Update the Apache PHP-FPM Configuration
Apache must be switched from the PHP 8.4 FPM configuration to PHP 8.5. This involves disabling the old FPM configuration, enabling the new one, and restarting both services.
Disable the PHP 8.4 FPM configuration for Apache:
sudo a2disconf php8.4-fpm
Enable the PHP 8.5 FPM configuration:
sudo a2enmod proxy_fcgi setenvif
sudo a2enconf php8.5-fpm
Enable the PHP 8.5 FPM service so it starts automatically at boot:
sudo systemctl enable php8.5-fpm
Restart PHP-FPM first so the socket is ready before Apache attempts to connect to it:
sudo systemctl restart php8.5-fpm
sudo apache2ctl configtest
sudo systemctl restart apache2
Confirm the PHP 8.5 FPM socket exists:
ls /run/php/php8.5-fpm.sock
NOTE: If this command returns
No such file or directory, PHP 8.5 FPM is not running or failed to start. Runsudo systemctl status php8.5-fpmto see the reason. A missing socket will cause Apache to return a 503 error for PHP requests handled by that FPM configuration.
Verify the Upgrade
PHP CLI Version
php -v
The output should now report PHP 8.5. If it still shows 8.4, the php command is resolving to the PHP 8.4 binary, which the alternatives system controls. Update it explicitly:
sudo update-alternatives --set php /usr/bin/php8.5
This affects only the CLI binary. Apache serves PHP through the PHP-FPM socket which is determined by the FPM configuration instead of the alternatives setting. WP-CLI and any cron jobs that invoke php directly are affected by the alternatives setting and will use whichever version the php command resolves to.
PHP-FPM Status
sudo systemctl status php8.5-fpm
Confirm PHP-FPM is being used by Apache by creating a temporary info file:
echo "<?php phpinfo(); ?>" | sudo tee /www/example-com/public_html/phpinfo.php
Navigate to https://www.example.com/phpinfo.php in a browser and confirm that the Server API line reads FPM/FastCGI and the PHP Version shows 8.5. Remove the file immediately after confirming the PHP version and FPM configuration. Do not leave a publicly accessible phpinfo.php file on a production server.
sudo rm /www/example-com/public_html/phpinfo.php
Apache Configuration Syntax Check
sudo apache2ctl configtest
The output should end with Syntax OK.
MariaDB Status
sudo systemctl status mariadb
Test a PHP database connection by logging in to the application and confirming it is functioning as expected. WordPress will report a missing MySQL extension if mysqli is not loaded, and will display an Error establishing a database connection message if the extension is loaded but the database is unreachable.
Troubleshooting
Apache Returns 503 for All PHP Requests
A 503 error after the upgrade almost always means the PHP-FPM socket is missing or PHP-FPM is not running. Check the Apache error log for the specific message:
sudo tail -n 50 /var/log/apache2/error.log
If the error log shows AH02454: FCGI: attempt to connect to Unix domain socket /run/php/php8.5-fpm.sock failed, PHP-FPM is not running, or the socket path does not match what Apache expects. Verify the socket exists:
ls /run/php/php8.5-fpm.sock
If it is missing, check the PHP-FPM service status and journal for the failure reason:
sudo systemctl status php8.5-fpm
sudo journalctl -u php8.5-fpm -n 50
Common causes include a configuration error in /etc/php/8.5/fpm/php.ini (check with sudo php-fpm8.5 -t) or a stale or conflicting socket file.
WordPress Reports a Database or MySQL Extension Error
If WordPress reports that the PHP installation is missing the MySQL extension, the mysqli extension is not loaded. Verify that it is loaded under PHP 8.5:
php8.5 -m | grep mysqli
The mysqli extension should appear in the output. If it does not, install the PHP 8.5 MySQL package:
sudo apt install -y php8.5-mysql
sudo systemctl restart php8.5-fpm
If the extension is present, or if WordPress displays Error establishing a database connection instead, check the WordPress wp-config.php file to confirm the database credentials are correct and the MariaDB service is running.
PHP Fatal Errors in the Error Log
After upgrading, monitor the Apache error log for fatal errors generated by PHP:
sudo tail -f /var/log/apache2/error.log
Fatal errors can indicate code that is incompatible with the installed PHP version. The error log will identify the file and line number. If the error is in a plugin, update the plugin to a compatible version or temporarily disable it to restore website functionality while investigating.
PHP CLI Still Reports the Previous Version
If php -v still reports the previous version after running update-alternatives, confirm which binary the php command resolves to:
which php
ls -la $(which php)
If the symlink still points to the previous PHP binary, set it explicitly:
sudo update-alternatives --set php /usr/bin/php8.5
Verify all registered alternatives to see what versions are available:
sudo update-alternatives --list php
Extension Missing After Upgrade
If a PHP extension that was present under 8.4 is not available under 8.5, it was not included in the install command. List the extensions available to PHP 8.5 from the CLI:
php8.5 -m
Compare against the extensions loaded under PHP 8.4:
php8.4 -m
Install any missing extensions by their PHP 8.5 package name:
sudo apt install -y php8.5-[extension-name]
sudo systemctl restart php8.5-fpm
Remove PHP 8.4
After confirming PHP 8.5 is working correctly and the application is functioning as expected, remove the PHP 8.4 packages. Running two PHP versions simultaneously is not inherently harmful, but it consumes disk space and leaves unused packages on the server that no longer serve a purpose once the upgrade is confirmed.
Stop and disable the PHP 8.4 FPM service before removing the packages:
sudo systemctl stop php8.4-fpm
sudo systemctl disable php8.4-fpm
Remove all PHP 8.4 packages:
sudo apt purge 'php8.4*' -y
sudo apt autoremove -y
Confirm PHP 8.4 packages are gone:
dpkg -l | grep php8.4
The command should return no output. If any packages remain, run sudo apt purge with the specific package names listed in the output.
Summary
Upgrading PHP on a self-managed Debian LAMP stack is straightforward. The process is: check plugin compatibility, take a snapshot, add the Sury repository, install the new PHP version and its extensions, port the php.ini customizations, switch the Apache PHP-FPM configuration from the old version to the new one, restart both services, verify the upgrade, and remove the old version.
The same general process applies to future PHP version upgrades; substitute the relevant version numbers and review the migration guide for any version-specific changes. The troubleshooting section covers several common failure modes that can occur during a PHP version upgrade.