[PHP-DEV] [Discuss] Add PDO disconnect() and isConnected()

Hello all,

I am announcing discussion phase of RFC “Add PDO disconnect() and isConnected()”. As the title suggests, this proposes to add a PHP interface to disconnect a PDO client, an alternative to the object destructor.

Thank you in advance for your consideration and guidance.

https://wiki.php.net/rfc/pdo_disconnect

-Robert Wolf

I find this proposal to be a backwards step in the age when we are
moving away from resources and their explicit closure. We have
disabled this in PHP 8.0 for curl_close(), imagedestroy(),
openssl_pkey_free(), shmop_close() and xml_parser_free(). Sure,
mysqli_close() still works, but the whole extension is mostly a
historical artefact and a bunch of bad design choices due to what that
extension is (quick replacement of mysql_* API). PDO was designed much
better and it deliberately avoided the foot gun that is explicit
connection closure. I really wish we would not introduce bad design
choices into the language, and because of this, I wish this proposal
were unsuccessful.

On Tue, Sep 30, 2025 at 4:56 PM Kamil Tekiela <tekiela246@gmail.com> wrote:

I find this proposal to be a backwards step in the age when we are
moving away from resources and their explicit closure. We have
disabled this in PHP 8.0 for curl_close(), imagedestroy(),
openssl_pkey_free(), shmop_close() and xml_parser_free(). Sure,
mysqli_close() still works, but the whole extension is mostly a
historical artefact and a bunch of bad design choices due to what that
extension is (quick replacement of mysql_* API). PDO was designed much
better and it deliberately avoided the foot gun that is explicit
connection closure. I really wish we would not introduce bad design
choices into the language, and because of this, I wish this proposal
were unsuccessful.

All of the foot gun examples you listed are such because that historic design pattern required explicit resource frees, and they are foot guns because it is easy to forget doing that.
Also, mysqli_close() is the only one that handles a stateful network connection and not a local resource, which is a good reason why it still works.

There are legitimate use cases where you may want to explicitly and immediately close a network connection, even if PHP would do it eventually.

Cheers,
Andrey.

I don't really see how it would be a bad thing.

This is very useful when you have scripts that are running for a very
long time (eg. daemons).

On Tue, 30 Sept 2025 at 15:42, Andrey Andreev <narf@devilix.net> wrote:

On Tue, Sep 30, 2025 at 4:56 PM Kamil Tekiela <tekiela246@gmail.com> wrote:

I find this proposal to be a backwards step in the age when we are
moving away from resources and their explicit closure. We have
disabled this in PHP 8.0 for curl_close(), imagedestroy(),
openssl_pkey_free(), shmop_close() and xml_parser_free(). Sure,
mysqli_close() still works, but the whole extension is mostly a
historical artefact and a bunch of bad design choices due to what that
extension is (quick replacement of mysql_* API). PDO was designed much
better and it deliberately avoided the foot gun that is explicit
connection closure. I really wish we would not introduce bad design
choices into the language, and because of this, I wish this proposal
were unsuccessful.

All of the foot gun examples you listed are such because that historic design pattern *required* explicit resource frees, and they are foot guns because it is easy to forget doing that.
Also, mysqli_close() is the only one that handles a stateful network connection and not a local resource, which is a good reason why it still works.

There are legitimate use cases where you may want to explicitly and immediately close a network connection, even if PHP would do it eventually.

Cheers,
Andrey.

By foot gun, I meant that when such a method exists, the developer can
never be sure that the PDO object is in a consistent state. As long as
the PDO object is accessible, closing it in one place in the code
means that there exists another place in the code where the object is
accessible but unusable. This is what gets so many mysqli users.

Another issue is that if you call disconnect on PDO object, but you
still have PDOStatement with unfetched data, you silently lose the
data or get an exception. This situation is more difficult to
accidentally arrive at, but still possible. You also lose the ability
to call methods such as PDOStatement::execute(). This is not possible
today, but by adding disconnect method we introduce a way in which
this is possible.

PDO isn't a new extension. It has done well without such a function
for many years. Maybe there are legitimate use cases for this, but
there are also alternatives. Pretty much every time I hear the
argument that it would be nice if PDO had it, I can reply with: you
can just design your code in a way that doesn't need it.

The disconnect method isn't needed for long-running scripts. PHP will
disconnect automatically when it determines that the connection is no
longer needed, and only then. It's the responsibility of the developer
to ensure that they don't keep variables around that aren't necessary
anymore.

I find this proposal to be a backwards step in the age when we are
moving away from resources and their explicit closure. We have
disabled this in PHP 8.0 for curl_close(), imagedestroy(),
openssl_pkey_free(), shmop_close() and xml_parser_free().

Thank you for providing these recent examples of resource-to-object conversions. As you well know, PDO is an object which also optionally uses PHP persistent resources to facilitate connection re-use across PHP requests, a feature which I don’t believe has a parallel in object space. Perhaps therein lies a feature request, i.e. to allow an object to be made persistent in the same way a resource can.

However, as there is no present path for PDO’s conversion away from PHP persistent resources, the prior examples you highlight seem to support an explicit close interface in PDO, in that so long as PHP resources are involved, a close method is warranted.

PDO was designed much
better and it deliberately avoided the foot gun that is explicit
connection closure.

I’ll push back on the notion that disconnect() is likely to be a foot gun.

In general, a held PDO object does not guarantee an active connection to a database. Remote connection closures do occur. Networks falter and fail. A robust application necessarily accounts for connectivity failure states, and in the case of PDO, is likely validating the success of every database interaction and reacting accordingly.

Considering, an implementation which unwittingly invokes disconnect() and permits continued use of the same PDO for database interactions will at least not error in novel ways. The recommendation for avoiding such mistakes in implementation would be the same which the community has long advocated for - decorate your PDOs.

Maybe there are legitimate use cases for this, but
there are also alternatives.

I listed a couple use cases in the RFC, which I’ll quote below for some added context.

  • Efficient management of database resources across periods of application idleness, opening and closing connection as needed.
  • Interoperability with database environment imposing timeout or other session constraints, necessitating multiple connections during script execution.
  • Abnormal termination procedure in which database closure is highly prioritized, e.g. security violation.
  • Testing purposes, e.g. simulation of remote connection failure.

Pretty much every time I hear the
argument that it would be nice if PDO had it, I can reply with: you
can just design your code in a way that doesn’t need it.

I tried responding to this in the RFC, also quoted below.

PHP makes the implementation of a decorator simple enough through magic methods like __call and __get, but this is complicated in PDO by the PDO statement object, which holds reference to a PDO object, and so must also be reference-managed. A leak-proof decorator should thus override PDO::prepare() and PDO::query() to also prevent the leak of the PDO statement object, likely requiring additional interfaces to otherwise interact with prepared PDO statements, to e.g. bind parameters and execute them, and queried PDO statements, to e.g. fetch one row, N rows, one column, etc. This prescribed implementation pattern is burdensome.

For persistent PDO objects, the user has no native capacity to close a connection, given that the database handle is inaccessible and registered as a PHP persistent resource, which remains until the PHP process terminates. To ensure database connectivity across subsequent PHP requests, each new PDO object includes a liveness check on the persistent connection, possibly prompting a new connection. This has meant the burden of defining a viable database connection resides within the database driver’s liveness check, and that an outcome differing with actual viability as it concerns a given application results in a non-viable database connection for all subsequent PHP requests. The proposed disconnect() thus grants the user the capacity to declare a connection as no-longer viable.

On Tue, Sep 30, 2025, at 10:13 AM, Kamil Tekiela wrote:

By foot gun, I meant that when such a method exists, the developer can
never be sure that the PDO object is in a consistent state. As long as
the PDO object is accessible, closing it in one place in the code
means that there exists another place in the code where the object is
accessible but unusable. This is what gets so many mysqli users.

Another issue is that if you call disconnect on PDO object, but you
still have PDOStatement with unfetched data, you silently lose the
data or get an exception. This situation is more difficult to
accidentally arrive at, but still possible. You also lose the ability
to call methods such as PDOStatement::execute(). This is not possible
today, but by adding disconnect method we introduce a way in which
this is possible.

PDO isn't a new extension. It has done well without such a function
for many years. Maybe there are legitimate use cases for this, but
there are also alternatives. Pretty much every time I hear the
argument that it would be nice if PDO had it, I can reply with: you
can just design your code in a way that doesn't need it.

The disconnect method isn't needed for long-running scripts. PHP will
disconnect automatically when it determines that the connection is no
longer needed, and only then. It's the responsibility of the developer
to ensure that they don't keep variables around that aren't necessary
anymore.

I generally agree that there's little value to a disconnect() action; unset($pdo) is already sufficient.

What would be valuable is easier RE-connection logic. Either PHP or MySQL may terminate an idle connection, which is a concern in long-running processes (Queue workers, ReactPHP, Franken, etc.). Tools like Doctrine have built their own refresh logic in, although they're not always consistent with each other or obvious to use. Having some kind of reconnection logic built into PDO that "just works" would be very valuable.

What that would look like, I'm not sure. Just spitballing:

// After X seconds, drop and reopen the connection the next time it's used.
$pdo->reconnectAfter($seconds);

--Larry Garfield

Le 30 sept. 2025 à 17:40, Larry Garfield larry@garfieldtech.com a écrit :

What would be valuable is easier RE-connection logic. Either PHP or MySQL may terminate an idle connection, which is a concern in long-running processes (Queue workers, ReactPHP, Franken, etc.). Tools like Doctrine have built their own refresh logic in, although they’re not always consistent with each other or obvious to use. Having some kind of reconnection logic built into PDO that “just works” would be very valuable.

What that would look like, I’m not sure. Just spitballing:

// After X seconds, drop and reopen the connection the next time it’s used.
$pdo->reconnectAfter($seconds);

–Larry Garfield

Auto-reconnection is dangerous, because database engines are stateful. For example, disaster will happen if disconnection had occurred in the middle of a transaction…

—Claude

On Tue, Sep 30, 2025, at 3:08 PM, Claude Pache wrote:

Le 30 sept. 2025 à 17:40, Larry Garfield <larry@garfieldtech.com> a écrit :

What would be valuable is easier RE-connection logic. Either PHP or MySQL may terminate an idle connection, which is a concern in long-running processes (Queue workers, ReactPHP, Franken, etc.). Tools like Doctrine have built their own refresh logic in, although they're not always consistent with each other or obvious to use. Having some kind of reconnection logic built into PDO that "just works" would be very valuable.

What that would look like, I'm not sure. Just spitballing:

// After X seconds, drop and reopen the connection the next time it's used.
$pdo->reconnectAfter($seconds);

--Larry Garfield

Auto-reconnection is dangerous, because database engines are stateful.
For example, disaster will happen if disconnection had occurred in the
middle of a transaction...

—Claude

All the more reason that the logic should be implemented once in PDO and then shared, rather than everyone having to figure it out in user space themselves.

I'm not suggesting that PDO actively try to disconnect all the time. But if the connection is "stale," it should be able to restart it without making the user faff about to do so. (Whether that's via detecting that it's gone away, a timer, or whatever else, I'm very flexible.)

--Larry Garfield

Le 30 sept. 2025 à 14:49, Robert Wolf rposky@gmail.com a écrit :

Hello all,

I am announcing discussion phase of RFC “Add PDO disconnect() and isConnected()”. As the title suggests, this proposes to add a PHP interface to disconnect a PDO client, an alternative to the object destructor.

Thank you in advance for your consideration and guidance.

https://wiki.php.net/rfc/pdo_disconnect

-Robert Wolf

Hi,

I’ve reviewed my uses of mysqli->close() in the wrapper class around mysqli I wrote several years ago. All of them were useless, and I have just deleted them after having carefully checked the documentation. Here is the most obvious case (yes, this is real code):


public function __destruct() {
if ($this->link !== null) {
@ $this->link->close();
$this->link = null;
}
}

I wished that mysqli->close() were never implemented…

Methods like mysqli->close() are innocuous by themselves. The issue is that users are tempted, even incited, to do manual operations that are very well done automatically (in this case, by the garbage collector). They are also driven to ask themselves questions that they don’t need to bother (“what if disconnection fails?”).

If you still have good reasons to add such a method in pdo. I recommend to use a name that deters users from using it in normal operations, e.g. pdo->debug_manual_disconnect().

—Claude

Le 30 sept. 2025 à 23:07, Larry Garfield <larry@garfieldtech.com> a écrit :

On Tue, Sep 30, 2025, at 3:08 PM, Claude Pache wrote:

Le 30 sept. 2025 à 17:40, Larry Garfield <larry@garfieldtech.com> a écrit :

What would be valuable is easier RE-connection logic. Either PHP or MySQL may terminate an idle connection, which is a concern in long-running processes (Queue workers, ReactPHP, Franken, etc.). Tools like Doctrine have built their own refresh logic in, although they're not always consistent with each other or obvious to use. Having some kind of reconnection logic built into PDO that "just works" would be very valuable.

What that would look like, I'm not sure. Just spitballing:

// After X seconds, drop and reopen the connection the next time it's used.
$pdo->reconnectAfter($seconds);

--Larry Garfield

Auto-reconnection is dangerous, because database engines are stateful.
For example, disaster will happen if disconnection had occurred in the
middle of a transaction...

—Claude

All the more reason that the logic should be implemented once in PDO and then shared, rather than everyone having to figure it out in user space themselves.

I'm not suggesting that PDO actively try to disconnect all the time. But if the connection is "stale," it should be able to restart it without making the user faff about to do so. (Whether that's via detecting that it's gone away, a timer, or whatever else, I'm very flexible.)

--Larry Garfield

Database connections are full of state (apart from transactions, there are also sql variables, temporary tables, and probably other stuff I am not aware of), thus auto-reconnection cannot be transparent in the general case. In specific scenarios, this is ok, but I doubt that it is best managed by a generic extension like pdo.

—Claude

I generally agree that there’s little value to a disconnect() action; unset($pdo) is already sufficient.

See the point again about persistent connections. The user has no means to disconnect in that case.

I recommend to use a name that deters users from using it in normal operations, e.g. pdo->debug_manual_disconnect().

Considering the above as well, a possible stance to take could be to introduce it as persistent_disconnect(). We could then decide whether it should function on “regular” connections as well.

On Wed, 1 Oct 2025 at 14:45, Robert Wolf <rposky@gmail.com> wrote:

> I generally agree that there's little value to a disconnect() action; unset($pdo) is already sufficient.

See the point again about persistent connections. The user has no means to disconnect in that case.

> I recommend to use a name that deters users from using it in normal operations, e.g. pdo->debug_manual_disconnect().

Considering the above as well, a possible stance to take could be to introduce it as persistent_disconnect(). We could then decide whether it should function on "regular" connections as well.

This sounds better, but I would argue that if it's a PERSISTENT
connection, then it should be impossible for the user to close it. The
idea is that the connection should remain open after being established
and should only close when the server restarts. What scenario would
necessitate the user to close a connection that should never close?

On 01/10/2025 14:55, Kamil Tekiela wrote:

This sounds better, but I would argue that if it's a PERSISTENT
connection, then it should be impossible for the user to close it. The
idea is that the connection should remain open after being established
and should only close when the server restarts. What scenario would
necessitate the user to close a connection that should never close?

As I understand it, at least in the case of MySQL, the state of persistent connections is not managed by MySQL, but by the client (PHP). This means that it's (at least theoretically) possible for a connection to end up in an undesirable state, in which case there should be a way to close it so it's not reused.

I think a disconnect method should be provided, with the proviso that there should be prominent warnings regarding state management on the documentation.

I've seen developers getting into trouble after attempting to implement automatic reconnection in their code with the existing PDO capabilities, so this already happens anyway.

If something is primarily a footgun, I can see that as reasoning for not providing it. But a kitchen knife is equally apt at cutting food and fingers. The latter is not a good reason to not have one in the kitchen - people can learn to use them safely with adequate instruction.

---

As an aside, the manual is unclear on how much management of persistent connections PDO does. I have an open issue on this: [Docs] PDO MySQL behavior with persistent connections (compared to mysqli) · Issue #4540 · php/doc-en · GitHub

(I did have a brief look again and based on some further investigation I did based (initially) on the answer thecotne gave in the above linked issue, believe that answer may not be accurate, at least in its reasoning, and thus their conclusion is circumspect. Looking at this again is somewhere on my todo list, I think)

On Wed, 1 Oct 2025 at 15:45, AllenJB <php.lists@allenjb.me.uk> wrote:

As I understand it, at least in the case of MySQL, the state of
persistent connections is not managed by MySQL, but by the client (PHP).
This means that it's (at least theoretically) possible for a connection
to end up in an undesirable state, in which case there should be a way
to close it so it's not reused.

You are correct, and I can see this as a justification for adding a
dangerous function; however, the circumstances you describe are very
vague. What is this undesirable state, and how would someone be able
to determine in code that the connection is in an undesirable state?
More importantly, why would they need to close the connection when it
happens instead of restoring it to a working state? The most common
way I can imagine is if you acquire a lock on a table and then PHP
script gets aborted due to an unhandled exception from something else
(e.g. HTTP network request which failed due to outside reasons). But
in that case, the persistent connection should be cleaned up by the
custom error handler on the script's termination. Currently, there is
no way to do that other than manually trying to release all
locks/transactions/tables. A disconnect method would solve that, but
so would a method to trigger COM_CHANGE_USER, which is still a worse
solution than a simple function to reset the connection.

If borked persistent connections are a real problem that needs
solving, then I support adding a function to PDO to reset persistent
connections. In MySQL, it would trigger COM_RESET_CONNECTION, and in
other drivers an analogous solution would need to be found. This
avoids the problem of having the PDO instance in a borked state.

What I am trying to say is that there should be no need to ever close
a persistent connection. If it ever gets messed up, it should be
restored to the working state rather than being closed.

This sounds better, but I would argue that if it’s a PERSISTENT
connection, then it should be impossible for the user to close it. The
idea is that the connection should remain open after being established
and should only close when the server restarts.

I think this reads too much into the “persistent” language, which does not derive from PDO but rather PHP resources. PDO cannot guarantee a connection always be open, nor should it be defining what connection viability is - it’s an application-level concern, and an overreach.

What scenario would necessitate the user to close a connection that should never close?

I provided some examples in the thread as to why a user could want to close a connection, maybe unconvincingly.

What I am trying to say is that there should be no need to ever close
a persistent connection. If it ever gets messed up, it should be
restored to the working state rather than being closed.

Thinking along these lines, what could meet this objective and satisfy some of the concerns outlined here, would be an interface to declare the persistent connection as defunct, such that upon subsequent PDO creation, a new connection will be formed, and the former will be closed. This is distinct from a disconnect or reconnect procedure, and similar to failing a “liveness” check upon persistent PDO creation. Users could then effectively replace their persistent PDO in the same manner they would do so for a “regular” PDO.

Difficulties in unset($pdo) to force a disconnect are still present though perhaps can be mitigated with the refactoring efforts outlined in “Future Scope” to break apart the mutual PDO and PDO statement references.

Database connections are full of state (apart from transactions, there are also
sql variables, temporary tables, and probably other stuff I am not aware of),
thus auto-reconnection cannot be transparent in the general case. In specific
scenarios, this is ok, but I doubt that it is best managed by a generic extension
like pdo.

This is exactly why the ability to manually close the connection is badly needed. Just because a connection hasn't been lost doesn't mean it's in a usable state. PDO will happily hand you a reused connection that is not, in fact, still usable. The only way around this issue is to encapsulate PDO such that you can replace the useless instance with a new one, since you cannot currently close a connection that is in an error state.

-Jeff

On Wed, Oct 1, 2025, at 15:55, Kamil Tekiela wrote:

On Wed, 1 Oct 2025 at 14:45, Robert Wolf <rposky@gmail.com> wrote:

I generally agree that there’s little value to a disconnect() action; unset($pdo) is already sufficient.

See the point again about persistent connections. The user has no means to disconnect in that case.

I recommend to use a name that deters users from using it in normal operations, e.g. pdo->debug_manual_disconnect().

Considering the above as well, a possible stance to take could be to introduce it as persistent_disconnect(). We could then decide whether it should function on “regular” connections as well.

This sounds better, but I would argue that if it’s a PERSISTENT
connection, then it should be impossible for the user to close it. The
idea is that the connection should remain open after being established
and should only close when the server restarts. What scenario would
necessitate the user to close a connection that should never close?

Off the top of my head (and it depends on the actual database on the other end of the pipe):

  1. After grant/role revocation, password rotation, or a switch from read/write replicas. Existing sessions usually keep there their privileges in a lot of databases. So, you could argue this is a security issue for long-lived applications.
  2. Perhaps you want to free any and all advisory locks?
  3. Sometimes the handle is alive, but the network connection is dead (this is argued elsewhere though).
  4. I’ve had some fun bugs in the past with prepared statements crashing a db server (putting it in maintenance mode and serving no traffic) being shared between requests. If I could have slapped a “just close it until we figure out what is going on” statement in there, I would have.
  5. Replica promotion, primary failover, blue/green cutovers, firewall changes … all these need new connections.
    Right now, you have to jump through a number of hoops to do these types of operations.

— Rob

On 01/10/2025 15:45, AllenJB wrote:

As an aside, the manual is unclear on how much management of persistent connections PDO does. I have an open issue on this: [Docs] PDO MySQL behavior with persistent connections (compared to mysqli) · Issue #4540 · php/doc-en · GitHub

(I did have a brief look again and based on some further investigation I did based (initially) on the answer thecotne gave in the above linked issue, believe that answer may not be accurate, at least in its reasoning, and thus their conclusion is circumspect. Looking at this again is somewhere on my todo list, I think)

An update: Based on testing, PDO (MySQL) does not perform cleanup of state of persistent connections - this means transactions, temporary tables, locks and other stateful changes may remain, causing the connection to be in an unexpected state.

For details of my test see [Docs] PDO MySQL behavior with persistent connections (compared to mysqli) · Issue #4540 · php/doc-en · GitHub

In my opinion, this makes a method of forcing a (persistent) connection closed explicitly useful.

Hi,

Il 01/10/2025 20:07, Rob Landers ha scritto:

This sounds better, but I would argue that if it's a PERSISTENT
connection, then it should be impossible for the user to close it. The
idea is that the connection should remain open after being established
and should only close when the server restarts. What scenario would
necessitate the user to close a connection that should never close?

Off the top of my head (and it depends on the actual database on the other end of the pipe):

<snip>

Right now, you have to jump through a number of hoops to do these types of operations.

During the years I've seen so many horror stories related to usage of persistent connections. I would argue we should discourage their use (deprecation is my dream!) rather than encouraging it by adding new features.

My 2c.

Cheers
--
Matteo Beccati