Jonathan Bird Web Design & Development

Latest PHP Version: Current Release and Support Status

by Jonathan Bird

If you only want the number: PHP 8.5.9 is the latest stable release of PHP, published on 30 July 2026. The next branch, PHP 8.6, is currently at Beta 1 and is scheduled for general availability on 19 November 2026.

The version number on its own doesn't tell you much. For an application you have to keep running, what matters is how long your branch still gets security fixes and how much work it takes to move to one that does.

We maintain Laravel and Statamic applications for established organisations, so this comes round every year, usually somewhere between "the host just deprecated your PHP version" and "a dependency won't install any more". Below: current release numbers, every support date, the full PHP 8.6 schedule, how to check which PHP your server actually runs, and how to upgrade without taking production down.

Every version number, date, and code sample below was checked against php.net and run on real PHP 8.2 through 8.6 builds on 18 August 2026.

The Latest PHP Version Right Now

"Latest" means three different things depending on who's asking, so here are all three.

What you mean by "latest" Version Released Safe for production?
Latest stable PHP release PHP 8.5.9 30 July 2026 Yes
Latest stable branch PHP 8.5 20 November 2025 Yes
Latest preview build PHP 8.6.0 Beta 1 13 August 2026 No, testing only

Each supported branch gets its own point releases on the same day, so if you're pinned to an older branch, the current patch level for yours is here:

Branch Latest release Released Release type
PHP 8.5 8.5.9 30 July 2026 Security
PHP 8.4 8.4.24 30 July 2026 Security
PHP 8.3 8.3.33 30 July 2026 Security
PHP 8.2 8.2.33 30 July 2026 Security

Two things worth reading off that table. First, all four were security releases on the same day, which is the normal pattern: when a CVE lands, every supported branch gets patched together. Second, point releases arrive on a strict four-week cadence. Looking at the 2026 dates so far (15 January, 12 February, 12 March, 9 April, 7 May, 4 June, 2 July, 30 July), every gap is exactly 28 days. The next round is due 27 August 2026.

That predictability is genuinely useful. If your server is more than about six weeks behind the current patch number for its branch, nobody is applying updates.

Supported PHP Versions and End-of-Life Dates

PHP gives every branch two years of active support (bug fixes and security fixes, with regular point releases), followed by two more years of critical security fixes only. Four years total, starting from a new branch that lands in late November most years.

Branch Initial release Active support until Security support until Status on 18 August 2026
PHP 8.5 20 Nov 2025 31 Dec 2027 31 Dec 2029 Current stable, actively supported
PHP 8.4 21 Nov 2024 31 Dec 2026 31 Dec 2028 Actively supported
PHP 8.3 23 Nov 2023 31 Dec 2025 31 Dec 2027 Security fixes only
PHP 8.2 8 Dec 2022 31 Dec 2024 31 Dec 2026 Security fixes only, EOL 31 Dec 2026
PHP 8.1 and older End of life, unsupported

The dates come from PHP's supported versions page, which is the only source worth trusting for this.

What "Security Fixes Only" Actually Means

This phrase gets read as "still fine" far more often than it should be. In practice:

  • Bugs are not fixed. If you hit a non-security bug in PHP 8.3, the answer is "upgrade to 8.5". There will not be a patch.
  • Releases are as-needed, not scheduled. A quiet month means nothing was urgent, not that the branch is healthy.
  • Only critical security issues qualify. Lower-severity security bugs can sit unfixed on a security-only branch.
  • Your dependencies leave first. Package maintainers drop old PHP versions on their own timetable, usually well before PHP's official EOL. You'll feel this as composer update quietly refusing to move packages long before php.net calls your branch dead.

If you're on PHP 8.2, mark the date: 31 December 2026. After that there are no more upstream patches at all, and any CVE published in January 2027 stays open on your server permanently unless your OS vendor backports it for you.

The PHP 8.6 Release Schedule

PHP 8.6 entered its beta phase on 13 August 2026. The full published timetable:

Date Milestone
2 Jul 2026 Alpha 1
16 Jul 2026 Alpha 2
30 Jul 2026 Alpha 3
11 Aug 2026 All RFCs targeting 8.6 merged
13 Aug 2026 Beta 1 + soft feature freeze
27 Aug 2026 Beta 2
10 Sep 2026 Beta 3
22 Sep 2026 Hard feature freeze
24 Sep 2026 RC1
8 Oct 2026 RC2
22 Oct 2026 RC3
5 Nov 2026 RC4
19 Nov 2026 General availability

The release managers for 8.6 are Daniel Scherzer, Matteo Beccati, and Joe Ferguson.

The soft feature freeze at Beta 1 is the milestone that matters for planning. From 13 August, the feature set of PHP 8.6 is settled: all RFCs targeting it have concluded voting. Everything between now and November is stabilisation. That means it's safe to start testing your codebase against 8.6 now, because the language surface isn't going to shift underneath you again.

What is not safe is running it. Betas and RCs get no security support, and the ABI can still change, which means compiled extensions may need rebuilding between now and GA.

Which PHP Version Should You Use?

Here's how to decide, by situation:

  • New project starting today: PHP 8.5. It's the current stable branch with active support until the end of 2027 and security fixes until the end of 2029. Check that your framework, your host, and any compiled extensions you depend on support it first, but in August 2026 most of them do.
  • Existing production app on PHP 8.4: no urgency, but put 8.5 on the roadmap. Active support for 8.4 ends 31 December 2026, and a change freeze over Christmas eats the last of that window.
  • On PHP 8.3: you're on security-only support already. Security fixes stop on 31 December 2027, so schedule the move to 8.5 well before then.
  • On PHP 8.2: this is current work, not future maintenance. The branch dies on 31 December 2026.
  • On PHP 8.1 or older: you are running unsupported software on a public server. Treat it as a security issue with a deadline that has already passed.
  • PHP 8.6: test environments only until 19 November 2026. Getting your test suite green against the beta now is cheap; being surprised in December is not.

There is one perfectly good reason to sit on PHP 8.4 rather than jumping to 8.5: a dependency that hasn't caught up yet.

Your Framework Sets the Real Floor and Ceiling

PHP's own support dates are only half the picture. Your framework has its own supported PHP range, and the intersection is what you can actually run.

For Laravel:

Laravel Supported PHP Released Bug fixes until Security fixes until
Laravel 13 8.3 to 8.5 17 Mar 2026 Q3 2027 17 Mar 2028
Laravel 12 8.2 to 8.5 24 Feb 2025 13 Aug 2026 24 Feb 2027
Laravel 11 8.2 to 8.4 12 Mar 2024 3 Sep 2025 12 Mar 2026

Worth noting for anyone on Laravel 12: bug-fix support ended on 13 August 2026. That branch is now on security-only support, with the same "no more bug fixes" reality PHP 8.3 users are living with. Laravel 13 requires PHP 8.3 as a minimum, so if you're on Laravel 12 and PHP 8.2, you have two upgrades to sequence, and PHP goes first.

Statamic follows Laravel: Statamic 6 requires Laravel 12.40 or 13, so it inherits whatever PHP range those support. If you're weighing up who does that work, there's a separate guide on hiring a Laravel developer, and a page covering what we do as Laravel developers in Brisbane.

How to Check Which PHP Version You're Actually Running

This sounds trivial and it isn't, because a typical server has more than one PHP binary and they routinely disagree. The command-line PHP that runs your cron jobs and your artisan commands is frequently not the PHP-FPM build that serves your website. That mismatch has cost us real hours.

Start With the CLI

1php -v

Which prints something like:

1PHP 8.5.8 (cli) (built: Jul 6 2026 06:38:54) (NTS clang 15.0.0)
2Copyright (c) The PHP Group

Note the (cli) in the first line. That's the SAPI, and it's telling you this number applies to the command line only.

Then Check the One That Serves Your Site

For PHP-FPM (the usual setup behind nginx):

1php-fpm -v
1PHP 8.5.8 (fpm-fcgi) (built: Jul 1 2026 03:46:27) (NTS)

The (fpm-fcgi) confirms you're looking at the right binary. On a server with several versions installed, be explicit: /usr/sbin/php8.4-fpm -v, or on macOS with Homebrew, /opt/homebrew/opt/[email protected]/sbin/php-fpm -v.

The most reliable answer, though, is to ask the running application rather than a binary on disk. Drop this in your web root temporarily:

1<?php
2 
3header('Content-Type: text/plain');
4 
5printf("Version: %s\n", PHP_VERSION);
6printf("SAPI: %s\n", PHP_SAPI);
7printf("Binary: %s\n", PHP_BINARY);
8printf("php.ini: %s\n", php_ini_loaded_file() ?: '(none)');
9printf("Zend: %s\n", zend_version());

Here's that same file, run two ways on the same machine. First served over HTTP, by a PHP build that isn't the one on the PATH:

1Version: 8.6.0-dev
2SAPI: cli-server
3Binary: /opt/homebrew/Cellar/[email protected]/8.6.0_1/bin/php
4php.ini: /opt/homebrew/etc/php/8.6/php.ini
5Zend: 4.6.0-dev

And from the command line:

1Version: 8.5.8
2SAPI: cli
3Binary: /opt/homebrew/Cellar/php/8.5.8/bin/php
4php.ini: /opt/homebrew/etc/php/8.5/php.ini
5Zend: 4.5.8

Same script, two different PHP versions, two different php.ini files. That's the trap, and it's why "I checked, we're on 8.5" is not an answer until you say which 8.5 you checked. (That demonstration used PHP's built-in server, so the SAPI reads cli-server. On a real nginx box it will say fpm-fcgi, and under Apache's module it will say apache2handler. The point is the same: whatever value comes back is the one that matters, because that's the PHP actually running your site.)

Delete that file when you're done. Same goes for phpinfo(), which is the classic version of this and leaks considerably more: absolute paths, loaded extensions, environment variables, and your full ini configuration. It's a reconnaissance gift to anyone scanning your site. If you need phpinfo(), put it behind auth or run it from the CLI with php -i.

From Inside Laravel

1php artisan about
1Environment ................................................................
2Application Name ............................................. Jonathan Bird
3Laravel Version .................................................... 12.66.0
4PHP Version .......................................................... 8.5.8
5Composer Version .................................................... 2.10.1
6Environment .......................................................... local

One command for the PHP version, the Laravel version, the Composer version, and your cache states. It's the first thing we run on any app we've inherited. Just remember it reports the CLI PHP, because that's what's executing it. Run it over SSH and you're seeing your cron environment, not your web environment.

Ask Composer Whether Your Code Even Fits

Version numbers matter less than whether your dependencies agree with them. Composer will tell you directly:

1composer check-platform-reqs
1Checking platform requirements for packages in the vendor dir
2composer-runtime-api 2.2.2 success
3ext-curl 8.5.8 success
4ext-dom 20031129 success
5ext-mbstring * success provided by symfony/polyfill-mbstring
6ext-openssl 8.5.8 success

That validates the current machine. The far more interesting question is whether a future PHP version would work, and there's a command for that too:

1composer why-not php 8.6

Run against this very site, it returns:

1nette/schema v1.3.5 requires php (8.1 - 8.5)
2nette/utils v4.1.5 requires php (8.2 - 8.5)

Two transitive dependencies with an upper bound of PHP 8.5. Nothing in the application code blocks PHP 8.6; two packages nobody chose directly do. This is the fastest way to find out whether a PHP upgrade is a config change or a dependency project, so run it before you plan the work.

Version Gates in Code (and One Real Trap)

Inside PHP, you have two ways to branch on version:

1if (PHP_VERSION_ID >= 80500) {
2 // PHP 8.5 or newer
3}
4 
5if (version_compare(PHP_VERSION, '8.5.0', '>=')) {
6 // PHP 8.5 or newer
7}

They are not equivalent, and the difference bites when you're testing against a beta. PHP_VERSION_ID is computed as major * 10000 + minor * 100 + release, so it ignores any pre-release suffix entirely.

Running on a PHP 8.6 beta build:

1Running: 8.6.0-dev (PHP_VERSION_ID 80600)
2PHP_VERSION_ID >= 80600: true
3version_compare >= 8.6.0: false

Both are "correct" and they disagree. PHP_VERSION_ID says you're on 8.6.0 because the numbers match. version_compare() applies semver-style pre-release ordering, where 8.6.0-dev, 8.6.0beta1, and 8.6.0RC1 all sort below the final 8.6.0.

Which one you want depends on the question. For "does this build have the 8.6 feature I need?", PHP_VERSION_ID is right, because betas do have the features. For "is this a supported production release?", version_compare() is right, because betas are not. Picking the wrong one is how a compatibility shim silently disables itself on a test server.

Why Your Server Reports an Older Version Than You Expect

You check php -v on your Ubuntu box, it says 8.3.6, and the current 8.3 release is 8.3.33. Twenty-seven releases behind. Time to panic?

Usually not. Enterprise Linux distributions don't rebase PHP to new upstream point releases during a distribution's life. They freeze an upstream version and backport security fixes into it, keeping the upstream version number and incrementing their own package revision instead.

Real examples, as published in August 2026:

OS PHP branch Package version
Ubuntu 24.04 LTS 8.3 8.3.6-0ubuntu0.24.04.10
Ubuntu 22.04 LTS 8.1 8.1.2-1ubuntu2.25
Debian 13 (trixie) 8.4 8.4.23-1~deb13u1
Debian 12 (bookworm) 8.2 8.2.32-1~deb12u1

Ubuntu 24.04 says 8.3.6, which upstream released in April 2024. The .10 on the end is Ubuntu's tenth revision of that package, carrying backported fixes for everything patched since. So the version string is misleading but the machine may well be current.

Two important caveats:

  1. This only holds while the distro still supports that PHP branch. Ubuntu 22.04's PHP 8.1 went upstream-EOL on 31 December 2025. Canonical still patches it for the life of 22.04, but you're now depending on one vendor's backporting effort rather than the PHP project's. That's a meaningfully thinner safety net.
  2. You cannot tell from the version number alone. 8.1.2 with no revision suffix and 8.1.2-1ubuntu2.25 look nearly identical and are years apart in patch coverage. Check the full package version (dpkg -l | grep php or rpm -q php), not php -v.

If you want to actually track upstream releases on Debian or Ubuntu, the standard answer is OndÅ™ej Surý's PPA / repository, which packages every current PHP branch and follows upstream point releases. On RHEL and derivatives, Remi's repository plays the same role. On macOS, Homebrew's php formula tracks the current stable branch, with [email protected] through [email protected] installable alongside it, and the shivammathur/php tap adds older and pre-release builds (which is how the PHP 8.6 examples in this article were tested).

For containers, the official Docker images track upstream precisely, and publish preview tags alongside stable ones: php:8.5-fpm, php:8.4-cli, and php:8.6.0beta1-cli were all available in August 2026. Pin the full version in production. php:8.5-fpm will silently roll you onto a new point release on rebuild, which is usually what you want for security and occasionally what breaks your build at 4pm on a Friday.

What You Actually Gain by Upgrading

Support dates are the reason you must upgrade. Here's the reason you'd want to. Everything below was run on the version stated.

PHP 8.4: Property Hooks and Asymmetric Visibility

The two headline features both reduce boilerplate that PHP developers have been writing by hand for twenty years.

1class Invoice
2{
3 public private(set) string $reference;
4 
5 public string $customer {
6 get => $this->customer;
7 set (string $value) => trim($value);
8 }
9 
10 public function __construct(string $reference, string $customer)
11 {
12 $this->reference = $reference;
13 $this->customer = $customer;
14 }
15}
16 
17$invoice = new Invoice('INV-1042', ' Impact Office Supplies ');
18 
19var_dump($invoice->customer);
20// string(22) "Impact Office Supplies"
21 
22$invoice->reference = 'INV-9999';
23// Error: Cannot modify private(set) property Invoice::$reference from global scope

private(set) gives you a property that's publicly readable but only writable from inside the class, with no getter method required. Property hooks let a plain property normalise its own input. Between them, a large amount of accessor boilerplate simply stops being necessary.

PHP 8.4 also added array functions people have been pulling in from packages for years, and dropped the parentheses requirement on immediate method calls:

1$branches = ['8.2', '8.3', '8.4', '8.5'];
2 
3var_dump(array_find($branches, fn (string $b): bool => $b > '8.3')); // string(3) "8.4"
4var_dump(array_any($branches, fn (string $b): bool => $b === '8.5')); // bool(true)
5var_dump(array_all($branches, fn (string $b): bool => str_starts_with($b, '8.'))); // bool(true)
6 
7var_dump(new Invoice('INV-1043', 'ROH Wheels')->customer); // no wrapping parens needed

On PHP 8.3 that first class definition doesn't even parse: Fatal error: Multiple access type modifiers are not allowed.

PHP 8.5: The Pipe Operator, Clone With, and a Real URI Parser

The pipe operator is the one you'll notice daily. It turns inside-out nested calls into something you read left to right:

1$title = ' Latest PHP Version ';
2 
3$slug = $title
4 |> trim(...)
5 |> strtolower(...)
6 |> (fn (string $value): string => str_replace(' ', '-', $value));
7 
8var_dump($slug);
9// string(18) "latest-php-version"

clone with finally makes the "wither" pattern on readonly classes bearable. Before 8.5, changing one property on a readonly object meant unpacking the whole thing through get_object_vars() and rebuilding it. Now it's one call:

1final readonly class Money
2{
3 public function __construct(
4 public int $amount,
5 public string $currency,
6 ) {}
7 
8 public function withAmount(int $amount): self
9 {
10 return clone($this, ['amount' => $amount]);
11 }
12}
13 
14var_dump((new Money(2500, 'AUD'))->withAmount(3000));
15// object(Money)#2 (2) { ["amount"]=> int(3000) ["currency"]=> string(3) "AUD" }

And PHP finally has a standards-compliant URI parser built in, rather than parse_url(), which has never fully implemented any specification:

1$uri = new Uri\Rfc3986\Uri('https://www.php.net/supported-versions.php');
2 
3var_dump($uri->getHost(), $uri->getPath());
4// string(11) "www.php.net"
5// string(23) "/supported-versions.php"

Also in 8.5: array_first() and array_last(), the #[\NoDiscard] attribute for functions whose return value must not be ignored, static closures allowed in constant expressions (so you can put one in an attribute), persistent cURL share handles, and backtraces on fatal errors, which is a small change that pays for itself the first time you're staring at a Laravel 500 error caused by an execution timeout.

PHP 8.6: What's Already Landed

Feature freeze was 13 August 2026, so this list is settled. Everything below was run on a PHP 8.6 beta build.

Partial function application is the big one. You can now bind some arguments to a function and leave the rest as placeholders, producing a new callable:

1$toSlug = str_replace(' ', '-', ?);
2 
3var_dump(array_map($toSlug, ['latest php version', 'supported php versions']));
4// array(2) {
5// [0]=> string(18) "latest-php-version"
6// [1]=> string(22) "supported-php-versions"
7// }

That single ? replaces an entire category of throwaway arrow functions, and it pairs neatly with 8.5's pipe operator.

Readonly properties can declare defaults, which removes an awkward gap where a readonly property could only ever be set in a constructor:

1class Release
2{
3 public readonly string $channel = 'stable';
4 
5 public function __construct(public readonly string $version) {}
6}
7 
8$release = new Release('8.6.0');
9var_dump($release->channel); // string(6) "stable"
10 
11$release->channel = 'beta';
12// Error: Cannot modify readonly property Release::$channel

Enums support __debugInfo(), so an enum can control how it appears in var_dump() output:

1enum Branch: string
2{
3 case Php84 = '8.4';
4 case Php85 = '8.5';
5 
6 public function __debugInfo(): array
7 {
8 return ['branch' => $this->value, 'activeSupport' => $this === self::Php85];
9 }
10}
11 
12var_dump(Branch::Php85);
13// enum(Branch::Php85) (2) {
14// ["branch"]=> string(3) "8.5"
15// ["activeSupport"]=> bool(true)
16// }

#[\Override] now applies to class constants, including enum cases, so the compiler catches a constant you meant to override but misspelled:

1interface HasBranch
2{
3 const string CURRENT = '8.5';
4}
5 
6final class Current implements HasBranch
7{
8 #[\Override]
9 public const string CURRENT = '8.6';
10}

There's also a new Time\Duration class, a stream errors API, TLS session resumption and 0-RTT early data for stream contexts, a polling API, and a Uri\Rfc3986\UriBuilder to complement 8.5's URI extension.

Alongside that, 8.6 brings a substantial deprecation round: is_long(), is_integer(), is_double(), doubleval(), spl_object_hash(), spl_classes(), metaphone(), strcoll(), mysqli_get_charset(), and mbregex (because the underlying Oniguruma library is no longer maintained). None of them break anything in 8.6, but a deprecation is how PHP signals what's on track for removal in the next major version, so this is your advance notice.

How to Upgrade Without Taking Production Down

This is the part that decides whether the upgrade is a half-day or a fortnight.

1. Find Out What Blocks You Before Planning Anything

1composer why-not php 8.5

If this returns packages, that's your actual scope of work: either those packages have newer versions that support your target, or they're abandoned and need replacing. Find out now. This is the step that turns "quick PHP upgrade" into "and we also have to replace our PDF library", and you want that discovered on day one.

2. Lint the Whole Codebase Against the Target Binary

Before running a single test, parse every file with the PHP version you're moving to. Syntax and compile-time errors surface instantly and cost nothing to find:

1find app config routes database tests -name '*.php' -print0 \
2 | xargs -0 -P 4 -n 1 /usr/bin/php8.5 -l \
3 | grep -v '^No syntax errors'

Point -l at the target binary, not your current one. Anything printed is a file that won't even compile.

3. Turn Deprecations Into Something You Can See

This is where most upgrade pain actually lives, because deprecations are silent until they aren't. Here's a small file that's completely valid PHP:

1<?php
2 
3function reportTotal(int $cents = null): string
4{
5 $dollars = (integer) round($cents / 100);
6 
7 return "Total: {$dollars}";
8}
9 
10echo reportTotal(2500), "\n";
11 
12$cache = [];
13$cache[null] = 'value';

Run it on PHP 8.3 with error_reporting(E_ALL) and it's completely clean. Not one warning.

On PHP 8.4:

1Deprecated: reportTotal(): Implicitly marking parameter $cents as nullable is
2deprecated, the explicit nullable type must be used instead

On PHP 8.5:

1Deprecated: Non-canonical cast (integer) is deprecated, use the (int) cast instead
2Deprecated: reportTotal(): Implicitly marking parameter $cents as nullable is deprecated...
3Deprecated: Using null as an array offset is deprecated, use an empty string instead

Three real problems in a dozen lines, invisible on the version you're running. Scale that up to a codebase and you understand why upgrades stall.

So make deprecations loud in CI and staging. Set error_reporting = E_ALL and log rather than display them, then run your full test suite on the target version and read the log. Laravel has a dedicated channel for exactly this in config/logging.php, and it's switched off by default:

1'deprecations' => [
2 'channel' => env('LOG_DEPRECATIONS_CHANNEL', 'null'),
3 'trace' => env('LOG_DEPRECATIONS_TRACE', false),
4],

That 'null' default is why you've probably never seen a deprecation in laravel.log. On staging, point it somewhere real and turn tracing on:

1LOG_DEPRECATIONS_CHANNEL=stack
2LOG_DEPRECATIONS_TRACE=true

The stack trace is the part that matters, because it tells you whether the deprecation is in your code or inside a vendor package. That distinction changes the fix entirely: one is a five-minute edit, the other is a dependency upgrade.

For a static sweep without running anything, Rector configured with ->withPhpSets() will both find and automatically fix a large share of version-specific issues, and PHPStan will catch removed functions and changed signatures.

4. Check Your Extensions Separately

Composer's platform checks cover extensions declared in composer.json, but PECL extensions that only exist in your ini configuration (Redis, imagick, xdebug, ioncube, New Relic, and anything commercial) are their own migration. Compiled extensions must be rebuilt for each PHP minor version. Compare the two environments directly:

1diff <(php8.3 -m) <(php8.5 -m)

Commercial and proprietary extensions are the ones that most often block an upgrade outright, because their vendor sets the timetable, not you.

5. Roll It Out in the Right Order

Sequence matters more than speed:

  1. Local first, then CI. Get the full test suite green on the target version before touching a server.
  2. Staging on identical infrastructure. Same OS, same extensions, same FPM configuration, same opcache settings. A staging box built differently from production will happily hide the problem you're trying to find.
  3. CLI and web together. Update the FPM pool and the CLI binary, or you'll get cron jobs and queue workers running a different PHP version from your web requests. That produces bugs that only appear in queued jobs and are miserable to trace.
  4. Have the rollback ready before you start. With multiple PHP versions installed side by side, rolling back is a config change and an FPM restart. Know the exact command before you need it.
  5. Watch the logs for a full business cycle. Deprecations and edge-case failures show up on the paths your test suite doesn't cover: the monthly invoice run, the nightly ERP sync, the one report a single user opens on Fridays.

If nobody on your team owns this, it belongs in a website maintenance plan.

Common Mistakes

A few that come up repeatedly:

  • Assuming one PHP version per server. Check CLI, FPM, and any Apache module separately. They disagree more often than they agree.
  • Reading the distro patch number as the upstream one. 8.3.6-0ubuntu0.24.04.10 is not two years of missing security patches, whatever php -v implies.
  • Upgrading PHP and the framework in the same deploy. When it breaks, you won't know which one did it. Move PHP first, verify, then move the framework.
  • Trusting composer.json's "php": "^8.2" as evidence. That's the floor your app claims to support, not what the server runs and not what your dependencies allow. composer why-not is the real check.
  • Leaving phpinfo.php in the web root. It's still one of the most common findings in a basic security scan.
  • Treating EOL as a hard cliff. The practical deadline is earlier: it's the day a package you need stops supporting your version, and that's set by maintainers, not php.net.

Frequently Asked Questions

What is the latest version of PHP?

PHP 8.5.9, released on 30 July 2026, is the latest stable release. PHP 8.5 is the current stable branch, first released on 20 November 2025.

Is PHP 8.6 out yet?

Not as a stable release. PHP 8.6 is in beta, with Beta 1 published on 13 August 2026 and general availability scheduled for 19 November 2026. Feature freeze has passed, so the feature set is final, but it should only be used in test environments until GA.

Which PHP version should I use in production?

PHP 8.5 for anything new, assuming your dependencies allow it. PHP 8.4 is a reasonable conservative target but its active support ends 31 December 2026. Anything on 8.3 or below is already security-fixes-only.

When does PHP 8.2 reach end of life?

31 December 2026. After that it receives no further patches of any kind from the PHP project.

When does PHP 8.4 stop being supported?

Active support ends 31 December 2026 and security support ends 31 December 2028.

How do I check my PHP version?

php -v for the command line, php-fpm -v for the version serving your website, and php artisan about inside a Laravel app. Because those can differ, the definitive answer comes from a script that prints PHP_VERSION and PHP_SAPI and is served through the same path as your application. Delete it afterwards.

Is it safe to run a PHP version that's on security-only support?

For a limited period, with a plan. What you give up is bug fixes, non-critical security fixes, and, in practice, the willingness of package maintainers to support you. It's a holding position, not a destination.

Does upgrading PHP break my site?

It can, and the risk scales with how many versions you skip. Going 8.4 to 8.5 is usually uneventful. Going 8.0 to 8.5 crosses several rounds of deprecations and removals. The upgrade path above (dependency check, lint sweep, deprecation logging, staged rollout) is what keeps it predictable.

Which PHP version does Laravel 13 need?

PHP 8.3 as a minimum, supported through 8.5. Laravel 12 supports 8.2 through 8.5.

Verify Any of This Yourself

Version numbers go stale, including the ones on this page. These are the sources we check, and the ones you should trust over any blog post, this one included:

We keep this page current as releases land. Everything above was verified on 18 August 2026.

If you're staring at a PHP upgrade you'd rather not do yourself, or you've inherited an application on a version that's already past its end-of-life date, that's a fair bit of what we do. Get in touch and we'll tell you honestly how big a job it is.

Syntax highlighting by Torchlight

Your website should be a business asset, not a headache

Led by more than 15 years of commercial experience, our senior team helps Australian organisations ship websites that are fast, secure, accessible and built for the long term.

Planning a project?

Get a quote
Get a quote