[Solution] PHP mysql_* Deprecated — Replace with mysqli_* Migration
The original mysql_* extension was deprecated in PHP 5.5 and removed in PHP 7.0. It was replaced by mysqli_* (MySQL Improved) and PDO (PHP Data Objects), both of which support prepared statements, which are critical for preventing SQL injection. Migrating is mandatory — your code will not run on PHP 7.0+ without updating.
What You’ll See
On PHP 7.0+:
Fatal error: Uncaught Error: Call to undefined function mysql_connect()
On PHP 5.5 through 5.6 (deprecated mode):
Deprecated: mysql_connect(): The mysql extension is deprecated and will be removed in the future: use mysqli or PDO instead in /path/to/script.php on line X
Why Deprecated
The mysql_* extension was removed for several critical reasons:
- No prepared statements: Without prepared statements, every query required manual escaping, which developers frequently forgot, leading to SQL injection vulnerabilities.
- Not maintained: The extension had not received updates for years and was incompatible with modern MySQL features.
- Security: Prepared statements via
mysqlior PDO provide parametrized queries that inherently prevent injection attacks. - Features:
mysqlisupports transactions, multiple statements, and improved error handling.
Old Code (Deprecated)
// Connection
$conn = mysql_connect("localhost", "user", "password");
mysql_select_db("mydb", $conn);
// Simple query
$result = mysql_query("SELECT * FROM users WHERE id = 1", $conn);
$row = mysql_fetch_assoc($result);
echo $row['name'];
// Insert with manual escaping (SQL injection risk)
$name = $_POST['name'];
$query = "INSERT INTO users (name) VALUES ('" . mysql_real_escape_string($name) . "')";
mysql_query($query, $conn);
// Row count
$count = mysql_num_rows($result);
// Free result
mysql_free_result($result);
// Close connection
mysql_close($conn);
New Code — mysqli_* Approach
// Connection (object-oriented)
$conn = new mysqli("localhost", "user", "password", "mydb");
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
// Simple query
$result = $conn->query("SELECT * FROM users WHERE id = 1");
$row = $result->fetch_assoc();
echo $row['name'];
// Insert with prepared statement (SQL injection safe)
$stmt = $conn->prepare("INSERT INTO users (name) VALUES (?)");
$stmt->bind_param("s", $_POST['name']);
$stmt->execute();
$stmt->close();
// Row count
$count = $result->num_rows;
// Free result
$result->free();
// Close connection
$conn->close();
New Code — PDO Approach (Recommended)
// Connection
$pdo = new PDO(
"mysql:host=localhost;dbname=mydb;charset=utf8mb4",
"user",
"password",
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
]
);
// Simple query
$stmt = $pdo->query("SELECT * FROM users WHERE id = 1");
$row = $stmt->fetch();
echo $row['name'];
// Insert with prepared statement
$stmt = $pdo->prepare("INSERT INTO users (name) VALUES (:name)");
$stmt->execute(['name' => $_POST['name']]);
// Fetch all rows
$stmt = $pdo->query("SELECT * FROM users WHERE active = 1");
$rows = $stmt->fetchAll();
// Using transaction
$pdo->beginTransaction();
try {
$pdo->exec("UPDATE accounts SET balance = balance - 100 WHERE id = 1");
$pdo->exec("UPDATE accounts SET balance = balance + 100 WHERE id = 2");
$pdo->commit();
} catch (Exception $e) {
$pdo->rollBack();
throw $e;
}
Migration Steps
- Find all mysql_ calls*:
grep -rn "\bmysql_" --include="*.php" /path/to/project/
Choose your replacement:
mysqliis a closer drop-in match, but PDO is the modern standard and supports multiple database drivers.Replace the connection with either
new mysqli()ornew PDO().Convert every query that uses user input to a prepared statement with bound parameters. This is the most important step for security.
Replace row-count functions:
mysql_num_rows($result)becomes$result->num_rows(mysqli) or$stmt->rowCount()(PDO).Replace
mysql_fetch_*calls with$result->fetch_assoc()(mysqli) or$stmt->fetch()(PDO).Update error handling.
mysqlireturnsfalseon failure; PDO can throw exceptions withERRMODE_EXCEPTION.Test every database interaction in your application. This is a high-risk migration — do not skip testing.
For very large codebases, consider using Rector to automate the mechanical parts of the conversion.