← Home ← Codex ← DEBT
Browse by Category
+ added · updated 7d
← Back to glossary

mysql_* Functions — Why They Were Removed

PHP PHP 3.0+ Beginner
debt(d5/e5/b5/t7)
d5 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'specialist tool catches it' (d5). The detection_hints list Rector, Semgrep, and PHPStan — all specialist/SAST-category tools that must be explicitly run. The function calls are syntactically valid in PHP 5.x so no compiler error catches them; a default linter won't flag them without custom rules. On PHP 7+ they cause a fatal error at runtime (d9 side), but specialist static analysis tools bring it to d5.

e5 Effort Remediation debt — work required to fix once spotted

Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix mentions Rector's MysqlToMysqliRector for mechanical migration to mysqli_*, then a further conversion to PDO prepared statements. While Rector automates the first pass, the full remediation (converting to prepared statements, updating connection handling, adjusting error handling patterns) typically touches many files across the codebase. Not a single-line patch (e1/e3), but not a full architectural rework (e7/e9).

b5 Burden Structural debt — long-term weight of choosing wrong

Closest to 'persistent productivity tax' (b5). A codebase still using mysql_* is locked to PHP ≤5.6, blocking upgrades to any modern PHP version and all its ecosystem improvements. This affects multiple workstreams (dependency updates, security patching, framework upgrades) but the burden is contained to legacy codebases — once migrated, the burden disappears entirely, so it doesn't define the system's shape permanently.

t7 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'serious trap — contradicts how a similar concept works elsewhere' (t7). The misconception field states that mysql_real_escape_string() is believed to be a safe alternative to prepared statements, but character set attacks and certain query constructs can still bypass it. This is a serious trap: the function is named to suggest complete safety ('escape_string' implies injection prevention), yet competent developers familiar with escaping in other contexts will trust it incorrectly. The common_mistakes confirm this is the canonical wrong belief.

About DEBT scoring →

Also Known As

mysql_query mysql_connect mysql_fetch_array ext/mysql

TL;DR

The original mysql_* extension was removed in PHP 7.0 after years of deprecation — it lacked prepared statements, making parameterised queries impossible and SQL injection trivially easy.

Explanation

The mysql extension provided functions like mysql_connect(), mysql_query(), mysql_fetch_array(), and mysql_real_escape_string(). It had two critical problems: no prepared statements, and mysql_real_escape_string() could be bypassed in certain character sets. The mysqli extension added prepared statements in PHP 5, and PDO added a clean multi-database API. mysql_* was deprecated in PHP 5.5 and removed in PHP 7.0. Any codebase still using it cannot run on PHP 7+.

Common Misconception

mysql_real_escape_string() is a safe alternative to prepared statements — character set attacks and certain query constructs can still bypass it.

Why It Matters

PHP 5.x end-of-life means any codebase still on mysql_* is running an unsupported PHP version with no security patches — a double vulnerability.

Common Mistakes

  • Using mysql_real_escape_string() believing it prevents all SQL injection
  • Migrating to PHP 7 without replacing mysql_* calls (they will fatal error)
  • Copy-pasting mysql_* examples from old Stack Overflow answers

Code Examples

✗ Vulnerable
// mysql_ extension — removed in PHP 7:
$conn = mysql_connect('localhost', 'root', '');
$result = mysql_query('SELECT * FROM users');
while ($row = mysql_fetch_array($result)) {
    echo $row['name'];
}
✓ Fixed
// PDO — works across MySQL, PostgreSQL, SQLite:
$pdo = new PDO('mysql:host=localhost;dbname=app', 'user', 'pass');
$stmt = $pdo->prepare('SELECT * FROM users WHERE active = ?');
$stmt->execute([1]);
foreach ($stmt->fetchAll() as $row) {
    echo htmlspecialchars($row['name']);
}

Added 22 Mar 2026
Edited 23 Mar 2026
Views 37
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
1 ping T 0 pings W 1 ping T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 1 ping S 1 ping M 0 pings T 2 pings W 0 pings T 1 ping F 0 pings S 0 pings S 1 ping M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W
No pings yet today
No pings yesterday
Amazonbot 10 Scrapy 4 Ahrefs 3 ChatGPT 3 Perplexity 2 Google 2 Claude 2 SEMrush 1 Meta AI 1
crawler 24 crawler_json 4
DEV INTEL Tools & Severity
🔴 Critical ⚙ Fix effort: High
⚡ Quick Fix
Use Rector's MysqlToMysqliRector rule to mechanically migrate mysql_* to mysqli_*, then convert to PDO prepared statements
📦 Applies To
PHP 3.0+ web cli
🔗 Prerequisites
🔍 Detection Hints
mysql_connect() mysql_query() mysql_fetch_array() mysql_real_escape_string() anywhere in codebase
Auto-detectable: ✓ Yes rector semgrep phpstan
⚠ Related Problems
🤖 AI Agent
Confidence: High False Positives: Low ✓ Auto-fixable Fix: Medium Context: File Tests: Update
CWE-89


✓ schema.org compliant