Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

To display SQL database records in an HTML table with PHP, connect through PDO, run a SELECT query, fetch each row, and escape every value before writing it into the page. The example below uses MySQL, filters for active users with a prepared statement, and renders a fixed set of columns.

1. Connect to the database with PDO

PDO provides a consistent PHP interface, but you also need the driver for your database. For MySQL, that is typically PDO_MYSQL. Confirm that the driver is installed and enabled in the PHP environment running your application. PHP’s PDO driver documentation lists the available database drivers.

Keep credentials outside publicly accessible files, such as in environment-specific configuration, and grant the application only the database permissions it needs. Set PDO to throw exceptions so connection and query failures can be handled deliberately rather than silently ignored.

2. Query rows and render the table

This example selects three named columns, binds the status filter as a value, fetches rows with column-name keys, and escapes both headings and values for HTML text content.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
<?php
$pdo = new PDO(
    'mysql:host=localhost;dbname=app;charset=utf8mb4',
    $user,
    $password,
    [
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    ]
);

$stmt = $pdo->prepare(
    'SELECT id, name, email FROM users WHERE status = :status ORDER BY id'
);
$stmt->execute(['status' => 'active']);

$columns = ['id' => 'ID', 'name' => 'Name', 'email' => 'Email'];
$escape = static fn ($value): string => htmlspecialchars(
    (string) $value,
    ENT_QUOTES | ENT_SUBSTITUTE,
    'UTF-8'
);

echo '<table><thead><tr>';
foreach ($columns as $heading) {
    echo '<th>', $escape($heading), '</th>';
}
echo '</tr></thead><tbody>';

while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
    echo '<tr>';
    foreach (array_keys($columns) as $key) {
        echo '<td>', $escape($row[$key]), '</td>';
    }
    echo '</tr>';
}

echo '</tbody></table>';

Replace the connection details, table, columns, and filter with values appropriate to your application. The column labels and keys in $columns are fixed by the application; each key must match a column returned by the query. PDO::FETCH_ASSOC returns each row as an array keyed by column name, making the rendering loop easier to read. See the PDO::prepare() and PDOStatement::fetch() references.

3. Keep request data out of SQL syntax

If a filter comes from a query string, form, or other request, pass it as a prepared-statement parameter instead of concatenating it into SQL. For example, replace the fixed 'active' value with a validated request value passed to execute(). PDO supports named or question-mark placeholders; do not mix the two styles in one statement. PHP’s prepared-statement guidance explains the API. MySQL likewise recommends prepared statements through client interfaces such as PDO or MySQLi; see its prepared statements documentation and security guidelines.

Placeholders are for data values, not SQL identifiers such as a table name or sort-column name. If users can choose among columns or sort directions, map their selection to a fixed allow-list of valid identifiers before assembling that portion of the query.

4. Escape output for the HTML context

Database values are not automatically safe to print. A stored value may contain characters that a browser interprets as markup or script. For plain HTML text and quoted attributes, PHP’s htmlspecialchars() converts special characters; the example uses ENT_QUOTES | ENT_SUBSTITUTE and UTF-8. Use context-appropriate encoding if placing data in JavaScript, CSS, a URL, or another context instead of ordinary table text. Do not treat SQL parameterization as a substitute for output escaping: they address different risks.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

5. Choose fetching and pagination for the result size

The example fetches one row at a time, avoiding the extra step of loading the entire result into a PHP array. For a small result set, fetchAll(PDO::FETCH_ASSOC) can be convenient. For a large or unbounded table, do not render every record in one response: constrain the query, add server-side filters, or paginate results. PHP notes that some result-set processing is better handled by the database than by loading and manipulating all rows in PHP; see PDOStatement::fetchAll().

Common mistakes to avoid

  • No PDO driver: install or enable the driver matching the database; PDO alone cannot connect to it.
  • SQL built by concatenating request values: use placeholders and pass values to execute().
  • Unescaped output: escape each value at the point it is inserted into HTML.
  • Unexpected blank or missing cells: check that every key in the fixed column definition is selected by the query and spelled identically.
  • Slow or memory-heavy pages: limit the result set and use filtering or pagination rather than rendering an entire large table.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.