php / php/php-src

ext/mysqli: mysqli double increments num_active_persistent when using real_connect

Open
#22,631 5 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Bug Extension: mysqli Status: Needs Triage
Dominant language
C
Stars
40.4k
Forks
8.1k
Avg merge
2d 13h
Merged PRs (30d)
96

Description

Description

The following code:

<?php

$use_real_connect = true;

$host = "p:localhost";
$user = "root";
$password = "password";

for ($i = 0; $i < 100; $i++)
{
  if ($use_real_connect)
  {
    $mysql = mysqli_init();
    mysqli_real_connect($mysql, $host, $user, $password);
  }
  else
  {
    $mysql = mysqli_connect($host, $user, $password);
  }
  mysqli_close($mysql);
}

$stats = mysqli_get_links_stats();
var_dump($stats);

Resulted in this output:

array(3) {
  ["total"]=>
  int(0)
  ["active_plinks"]=>
  int(99)
  ["cached_plinks"]=>
  int(1)
}

But I expected this output instead:

array(3) {
  ["total"]=>
  int(0)
  ["active_plinks"]=>
  int(0)
  ["cached_plinks"]=>
  int(1)
}

The code gives the correct output if you turn off the $use_real_connect flag.

This is caused by the persistent branch of mysqli_common_connect incrementing num_inactive_persistent (mysqli_nonapi.c:179 in tag php-8.5.8) when a persistent connection is reused based on the connection hash, then jumping to the end: label, and incrementing it again under this condition:

// mysqli_nonapi.c:296
if (persistent && (new_connection || is_real_connect)) {
    MyG(num_active_persistent)++;
}

Because mysql_close has already been called on the persisted connection, we get a total increase in active persistent connections by 1.

I'm not entirely sure why || is_real_connect is needed in that check, it looks to me like new_connection still covers the persistent case.

EDIT: The consequence of this issue is that if you make a persistent connection a ton of times (say in a long-running php-fpm process), and then make a different connection that doesn't yet exist in the connections hash table, you will always fail with the error Too many open persistent links with a massively huge number of active persistent connections. Note that this does not actually leak connections to the server, you still are capped properly by at most mysqli.max_persistent.

PHP Version
PHP 8.5.8 (cli) (built: Jul  6 2026 16:48:54) (NTS)
Copyright (c) The PHP Group
Built by https://github.com/docker-library/php
Zend Engine v4.5.8, Copyright (c) Zend Technologies
    with Zend OPcache v8.5.8, Copyright (c), by Zend Technologies
Operating System

Debian 13.5

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with ext/mysqli/mysqli_nonapi.c, especially mysqli_common_connect and the persistent-connection accounting around the cited lines. Run the supplied reproducer with real_connect enabled, then verify that repeated reuse leaves active_plinks at 0 and cached_plinks at 1 without changing the non-real_connect behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
c, php
Domain
databases
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.