Connecting PHP to MySQL

Connect PHP to MySQL with PDO or optional MySQLi, set utf8mb4, load protected credentials, and diagnose connection failures.

Lesson 68 of 86Intermediate10 min read

A database connection creates a session between the PHP process and MySQL. It does not create your tables or verify that your application has chosen the right permissions. To connect reliably, you need the correct PHP driver, server address, credentials, database name, and character set. This reference shows PDO as the main course approach and MySQLi as an optional equivalent. It also explains localhost behavior, missing drivers, and the difference between authentication failure and unavailable servers. The examples use environment-supplied configuration and do not open a real external database connection during the lesson.

Check the runtime before the credentials

PDO is a general extension, while pdo_mysql is the specific driver needed for a MySQL DSN. MySQLi is a separate extension. Check the extensions loaded by the PHP process that serves your site, not only the CLI executable. Different PHP installations or configuration files can make php -m disagree with the web handler. A 'could not find driver' error points to driver setup, whereas an access-denied message usually means the server was reached but rejected authentication or account permissions. Confirm PHP and MySQL versions against the project's supported environment. Use a protected diagnostic route or deployment logs rather than leaving phpinfo() publicly available. That output can reveal paths, modules, and sensitive configuration useful to an attacker.

Choose the correct host and transport

In many Unix MySQL clients, localhost can select a Unix socket while 127.0.0.1 selects TCP. Exact behavior depends on the driver and platform, so use explicit host, port, or socket settings when diagnosing. Inside a container, localhost usually refers to that container, not a neighboring database service. Hosted databases may require a service hostname and verified TLS. A connection timeout can indicate network routing, firewall rules, name resolution, or unavailable service rather than a wrong password. Keep these diagnoses separate. Do not expose a database to the public internet merely to make a local connection string work. Use the deployment's intended network access and a narrowly permitted application account.

Configure PDO explicitly

A PDO MySQL DSN can include host, port, dbname, and charset=utf8mb4. Options should make error handling and row shape predictable: ERRMODE_EXCEPTION and FETCH_ASSOC are useful defaults. For MySQL, disabling emulated prepares can select native preparation where appropriate; test the queries you use because driver behavior and placeholder rules matter. Load credentials from protected runtime configuration and reject missing or empty required values rather than quietly connecting with insecure defaults. Construct the DSN from validated application configuration, not request input. A single request commonly creates or receives one connection that repositories reuse. Do not establish a new connection for every row in a loop. That adds latency and can overwhelm the server's connection budget.

Configure optional MySQLi consistently

MySQLi provides a constructor with host, username, password, database, port, and socket arguments. Set mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT) explicitly for exception behavior, then call set_charset('utf8mb4'). PHP version defaults have changed, so an explicit policy makes examples more predictable. Set required connection options before connecting when the option API requires that order, especially for TLS or timeouts. Avoid mixing procedural and object-oriented styles arbitrarily inside one file. MySQLi's optional track is useful for existing MySQL projects; it does not replace the course's PDO foundation. Both connections need the same care with permissions, prepared statements, and private logs.

Separate application and administrative accounts

The runtime account should receive only operations required by the application, often SELECT, INSERT, UPDATE, and DELETE on a defined schema. Creating or dropping schemas belongs to a controlled migration or administrative process using separate privileges. Never use a root account simply because a tutorial makes it convenient. Password rotation should change runtime configuration without requiring code edits. Limit who can read that configuration and avoid printing it during debugging. A development account and a production account should not share broad credentials. Connection success only proves that a session opened; queries can still fail because tables are missing, grants are narrower, or the selected database is wrong. Check expected schema versions during deployment.

Handle failure without leaking infrastructure

Catch connection exceptions at an application boundary, log an operation identifier and safe diagnostic details privately, and return a generic service-unavailable response appropriate to the request. Do not display the raw DSN, server hostname, password, or full exception stack to visitors. An outage may justify bounded retries or a maintenance response, but repeated authentication failures will not improve through blind retries. Set reasonable time budgets and monitor the number of active connections. Persistent connections introduce process-level reuse and state-management concerns; do not enable them automatically as a supposed performance fix. Measure whether connection overhead is a real bottleneck and understand the hosting environment's worker model first.

Practice task and worked solution

Create a connection factory for a small product application. The solution validates deployment settings, constructs one PDO connection per request, and passes it to repository functions. Provide a separate optional MySQLi factory with explicit reporting and utf8mb4 setup. Test missing driver, wrong database name, denied credentials, unreachable host, and a successful SELECT through a controlled local database. Classify each failure instead of recommending the same fix for all. Review the runtime account's grants and remove schema-administration privileges if requests do not need them. Verify the web runtime and CLI use compatible settings before running migration tooling.

Continue learning

Continue with PDO and MySQL, exceptions, and security.

The MySQLi connection guide explains connection parameters and client transport behavior.

Connecting PHP to MySQL Examples

Each example shows the code, the output it produces and what each part does.

Example 1

Build a PDO connection from protected settings

The variables must be injected by the server environment. This is illustrative PHP code requiring pdo_mysql and a reachable permitted database; it is not browser-runnable.

With correct configuration, driver, network access, and grants, the example prints Database session ready. Missing configuration or connection failures produce exceptions handled by the surrounding application. Actual server details are intentionally not printed.

PHP
<?php
$required = ['DB_HOST', 'DB_NAME', 'DB_USER', 'DB_PASSWORD'];
$config = [];
foreach ($required as $key) {
    $value = getenv($key);
    if ($value === false || $value === '') {
        throw new RuntimeException('Missing database configuration');
    }
    $config[$key] = $value;
}
$dsn = 'mysql:host=' . $config['DB_HOST']
     . ';dbname=' . $config['DB_NAME'] . ';charset=utf8mb4';
$pdo = new PDO($dsn, $config['DB_USER'], $config['DB_PASSWORD'], [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    PDO::ATTR_EMULATE_PREPARES => false,
]);
echo 'Database session ready.';
Output
With valid driver, configuration and access: Database session ready.

Connecting PHP to MySQL FAQ

Why does CLI connect but the website fails?

The command line and the web server may use different PHP configuration files, loaded extensions, environment variables or user accounts, and even reach the database through different networks. Compare php --ini with phpinfo() from the web server, and check which credentials each one actually receives.

Does localhost always mean TCP?

No. With MySQL client libraries, localhost often means a Unix socket file rather than a TCP connection to 127.0.0.1, and socket behaviour varies with configuration. If the socket path is wrong, use 127.0.0.1 to force TCP, or set the correct socket path explicitly.

Should I use root?

No. The root account can drop databases and create users, so a single injection bug would expose everything. Use a narrowly permitted application account that has only the privileges the application needs, such as SELECT, INSERT, UPDATE and DELETE on its own database.

Should every query reconnect?

No. Opening a connection takes time and server resources. Create one connection per request, usually in a small factory or container, and reuse the configured request connection where appropriate for every query in that request.

Connecting PHP to MySQL Exercises

Answer each one and check it instantly. If you get stuck, open the hint before the answer.

Multiple choicemedium

A container's localhost cannot reach a separate database container. What should be checked?

Connecting PHP to MySQL Quiz

2 questions to check what you learned.

  1. What does 'could not find driver' usually indicate?

    • A missing products table
    • An unavailable MySQL server port
    • The required PDO database driver is unavailable
    • A guaranteed wrong password
  2. Who should receive schema-administration privileges?

    • Every public request account automatically
    • Every anonymous visitor
    • The JavaScript client
    • A controlled migration or administrative account