Upgrade PHP on a Debian LAMP Stack
One of the core 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, upgrading in place is a matter of installing new packages and updating the Apache configuration. 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 your 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.3 as the installed version and PHP 8.4 as the target. Substitute your own version numbers wherever they appear in commands and file paths. The process is the same regardless of which version pair is involved.
NOTE: This guide covers upgrading between PHP releases (for example, PHP 8.3 to PHP 8.4) 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 stage you want to be in.
- 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 right time to upgrade is when your current version exits active support, not when it reaches end of life. 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 your application. WordPress core typically adopts new PHP releases quickly, while plugins may take longer to declare compatibility. Check the WordPress hosting requirements and test your plugin stack against the target version before upgrading a production server.
Before You Begin
Check for Plugin Compatibility Issues
Each new PHP version enforces stricter handling of some patterns that were silently permitted in earlier versions. Before upgrading, check whether your installed plugins have known compatibility issues with the target PHP version. Check that your themes and plugins explicitly support 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 first without switching Apache to use it, then review the application error log for deprecation notices and fatal errors. Each PHP version introduces deprecations for patterns that will become errors in the next major version. Catching them before the switch reduces the risk of unexpected failures.
Take a Snapshot
Take a snapshot of your instance before proceeding. A PHP upgrade is low-risk when following these steps, but having a restore point eliminates recovery time 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.
If you are using 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 you are working with the latest security patches for both components before adding a new PHP version on top. Installing PHP 8.4 is a separate step because it is a new package rather than an in-place upgrade of PHP 8.3.
sudo apt update && sudo apt upgrade -y
Review the output for any notices about held packages or configuration file prompts. If APT prompts you about configuration files, press N to keep your existing version.
NOTE: This guide uses
apt upgraderather thanapt full-upgrade. On a production server,apt upgradeis the safer choice for routine maintenance: it installs available updates but will not remove installed packages or introduce new dependencies that could disrupt the running stack.apt full-upgradeis more aggressive and is appropriate for major distribution upgrades, not routine patching.
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
Install PHP 8.4
Since both PHP 8.3 and PHP 8.4 are available from the same Sury repository, no repository configuration changes are required. If the Sury repository is not already configured on your server, follow the Add the Sury PHP Repository section of the install guide before continuing.
Install PHP 8.4 with PHP-FPM and the same extensions used in the install guide:
sudo apt install -y php8.4 php8.4-{common,fpm,mysql,curl,igbinary,imagick,intl,mbstring,xml,zip}
After installation, confirm the PHP 8.4 packages are present:
php8.4 -v
The output may already show PHP 8.4. If it still reports PHP 8.3, that is expected on some systems; the CLI default is updated in a later step.
Configure PHP 8.4 for Production
The PHP 8.4 configuration file at /etc/php/8.4/fpm/php.ini contains default values that are too conservative for most WordPress installations. Apply the same production settings used during the initial installation:
sudo sed -i 's/^memory_limit = .*/memory_limit = 256M/' /etc/php/8.4/fpm/php.ini
sudo sed -i 's/^upload_max_filesize = .*/upload_max_filesize = 64M/' /etc/php/8.4/fpm/php.ini
sudo sed -i 's/^post_max_size = .*/post_max_size = 64M/' /etc/php/8.4/fpm/php.ini
sudo sed -i 's/^max_execution_time = .*/max_execution_time = 120/' /etc/php/8.4/fpm/php.ini
sudo sed -i 's/^expose_php = .*/expose_php = Off/' /etc/php/8.4/fpm/php.ini
If you applied disable_functions on your PHP 8.3 installation, apply it to PHP 8.4 as well:
sudo sed -i 's/^disable_functions = .*/disable_functions = exec,passthru,shell_exec,system,proc_open,popen/' /etc/php/8.4/fpm/php.ini
If you made any other customizations to /etc/php/8.3/fpm/php.ini, compare both files before continuing:
diff /etc/php/8.3/fpm/php.ini /etc/php/8.4/fpm/php.ini
Review the diff output and port any intentional customizations from the 8.3 file to the 8.4 file. Ignore differences in version-specific default values; focus only on lines you changed deliberately.
Update the Apache PHP-FPM Configuration
Apache must be switched from the PHP 8.3 FPM configuration to PHP 8.4. This involves disabling the old FPM configuration, enabling the new one, and restarting both services.
Disable the PHP 8.3 FPM configuration for Apache:
sudo a2disconf php8.3-fpm
Enable the PHP 8.4 FPM configuration:
sudo a2enmod proxy_fcgi setenvif
sudo a2enconf php8.4-fpm
Enable the PHP 8.4 FPM service so it starts automatically at boot:
sudo systemctl enable php8.4-fpm
Restart PHP-FPM first so the socket is ready before Apache attempts to connect to it:
sudo systemctl restart php8.4-fpm
sudo apache2ctl configtest
sudo systemctl restart apache2
Confirm the PHP 8.4 FPM socket exists:
ls /run/php/php8.4-fpm.sock
NOTE: If this command returns
No such file or directory, PHP 8.4 FPM is not running or failed to start. Runsudo systemctl status php8.4-fpmto see the reason. A missing socket will cause Apache to return a 503 error for all PHP requests.
Verify the Upgrade
PHP CLI Version
php -v
The output should now report PHP 8.4. If it still shows 8.3, the system’s default CLI version has not been updated. This happens when multiple PHP versions are installed simultaneously; the alternatives system controls which binary the php command resolves to. Update it explicitly:
sudo update-alternatives --set php /usr/bin/php8.4
This affects only the CLI binary. Apache serves PHP through the PHP-FPM socket, not the CLI binary, so the version Apache uses is determined by the FPM configuration updated in the previous step, not by 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.4-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.4. Remove the file immediately after confirming:
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 your application and confirming it is functioning as expected. WordPress will display a database connection error on the front end if the PDO or MySQLi extension is missing or misconfigured, which is the most common post-upgrade issue.
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 you see AH02454: FCGI: attempt to connect to Unix domain socket /run/php/php8.4-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.4-fpm.sock
If it is missing, check the PHP-FPM service status and journal for the failure reason:
sudo systemctl status php8.4-fpm
sudo journalctl -u php8.4-fpm -n 50
Common causes include a configuration error in /etc/php/8.4/fpm/php.ini (check with sudo php-fpm8.4 -t) or a port conflict if another process is already using the socket path.
WordPress Shows a Database Connection Error
If WordPress loads but immediately shows a database connection error, the most likely cause is a missing or broken database extension. Verify the pdo_mysql and mysqli extensions are loaded under PHP 8.4:
php8.4 -m | grep -E 'pdo_mysql|mysqli'
Both should appear in the output. If either is missing, install the PHP 8.4 MySQL package:
sudo apt install -y php8.4-mysql
sudo systemctl restart php8.4-fpm
If the extensions are present and the error persists, check the WordPress wp-config.php file to confirm the database credentials are correct and the MariaDB service is running.
PHP Deprecation Notices or Fatal Errors in the Error Log
After upgrading, monitor the Apache error log for deprecation notices or fatal errors generated by PHP:
sudo tail -f /var/log/apache2/error.log
Deprecation notices indicate code that uses patterns the current PHP version has marked for removal in a future major release. They do not break functionality in the current version but should be treated as a warning that affected plugins or application code will need to be updated before the next major PHP upgrade. If the notice is in a plugin, check whether a newer version of the plugin addresses it.
Fatal errors are more serious and indicate code that is genuinely 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 site 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.4
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.3 is not available under 8.4, it was not included in the install command. List loaded extensions under PHP 8.4 to identify what is missing:
php8.4 -m
Compare against the extensions loaded under PHP 8.3:
php8.3 -m
Install any missing extensions by their PHP 8.4 package name:
sudo apt install -y php8.4-[extension-name]
sudo systemctl restart php8.4-fpm
Remove PHP 8.3
After confirming PHP 8.4 is working correctly and the application is functioning as expected, remove the PHP 8.3 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.3 FPM service before removing the packages:
sudo systemctl stop php8.3-fpm
sudo systemctl disable php8.3-fpm
Remove all PHP 8.3 packages:
sudo apt purge php8.3* -y
sudo apt autoremove -y
Confirm PHP 8.3 packages are gone:
dpkg -l | grep php8.3
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 when the stack was built with PHP-FPM and the Sury repository. The process is: check plugin compatibility, take a snapshot, install the new PHP version and its extensions, port your 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 process applies to future PHP version upgrades; substitute the relevant version numbers and follow the same sequence. The troubleshooting section covers the failure modes most likely to occur regardless of which version pair is involved.