Fix mysql_fetch_array() Expects Parameter 1 to Be Resource

By HeadsNTail Published 8 min read MySQL
Fix mysql_fetch_array() Expects Parameter 1 to Be Resource

You'll learn how to identify the failed MySQL query behind the "expects parameter 1 to be resource" warning and fix it using modern, reliable PHP database code.

Time needed: Approximately 10–20 minutes.

If you're maintaining an older PHP application, you may encounter an error like this:

Warning: mysql_fetch_array() expects parameter 1
to be resource, boolean given

The same warning can appear with several functions:

mysql_fetch_assoc() expects parameter 1 to be resource
mysql_fetch_row() expects parameter 1 to be resource
mysql_num_rows() expects parameter 1 to be resource

These warnings usually have one underlying cause: the SQL query failed, but the application tried to read its result anyway.

The fetch function is where the problem becomes visible. It usually isn't where the original mistake occurred.

We'll reproduce the issue using a small demo_users table, find the SQL error, and replace the legacy code with MySQLi or PDO.

Step 1: Create a Small MySQL Table for Testing

Before fixing the PHP code, we need a query that we know should work.

Open your MySQL terminal:

mysql -u root -p

Enter your database password when prompted.

On XAMPP, you can also use phpMyAdmin's SQL interface.

Create a test database and table:

CREATE DATABASE IF NOT EXISTS fetch_demo;

USE fetch_demo;

CREATE TABLE IF NOT EXISTS demo_users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100) NOT NULL
);

INSERT INTO demo_users (name)
VALUES ('Amina'), ('Ravi');

SELECT id, name FROM demo_users;

Expected result: MySQL returns two user records, assuming this is the first time you've inserted the sample data.

idname
1Amina
2Ravi

If you rerun the inserts, additional rows will appear because the IDs are automatically generated.

This table will be our running example.

If the final SELECT fails, correct the database or table setup before investigating PHP.

Step 2: Reproduce the Resource Warning in Legacy PHP

The original mysql_* extension is no longer available in modern PHP.

It was deprecated in PHP 5.5 and removed in PHP 7.0.

However, understanding its behavior is useful when repairing an old application.

The following example is for historical PHP 5 environments only. Do not use it in a new application.

<?php

$connection = mysql_connect(
    'localhost',
    'root',
    ''
);

mysql_select_db('fetch_demo', $connection);

$result = mysql_query(
    "SELECT id, name FROM missing_users",
    $connection
);

$row = mysql_fetch_assoc($result);

print_r($row);

Notice the table name:

SELECT id, name FROM missing_users

We created demo_users, not missing_users.

Because the requested table does not exist, mysql_query() returns false.

The next line passes that boolean into mysql_fetch_assoc().

But the legacy function expects a MySQL result resource.

That's why PHP reports that parameter 1 is not a resource.

Why does mysql_num_rows() show the same warning?

All these functions expect a valid query result.

Legacy functionPurpose
mysql_fetch_array()Fetch a row as an array
mysql_fetch_assoc()Fetch a row using column names
mysql_fetch_row()Fetch a numerically indexed row
mysql_num_rows()Count rows in a SELECT result

When the query fails, none of these functions receives the resource it needs.

Importantly, a successful SELECT returning zero rows is not a failed query.

An empty result can still be valid. In that case, the fetch function returns false because no row remains, and mysql_num_rows() returns zero.

Step 3: Find the SQL Error Before Calling Fetch

A common mistake is to change the fetch function without checking the SQL query.

That doesn't solve the underlying problem.

In a legacy PHP 5 application, the immediate diagnostic fix is:

<?php

$connection = mysql_connect(
    'localhost',
    'root',
    ''
);

if (!$connection) {
    die('Database connection failed.');
}

if (!mysql_select_db('fetch_demo', $connection)) {
    die('Database selection failed.');
}

$result = mysql_query(
    "SELECT id, name FROM missing_users",
    $connection
);

if ($result === false) {
    error_log(mysql_error($connection));
    die('Database query failed.');
}

while ($row = mysql_fetch_assoc($result)) {
    echo htmlspecialchars($row['name'], ENT_QUOTES, 'UTF-8');
}

Now the application checks whether the query succeeded before trying to fetch rows.

Expected result: Instead of producing the resource warning, the script logs the underlying database error and displays a generic failure message.

For our example, MySQL reports that the requested table does not exist.

Fix the query:

SELECT id, name FROM demo_users;

Other causes include misspelled column names, invalid SQL syntax, missing database permissions, and queries executed against the wrong database.

Never expose raw database error messages to public visitors. Log technical details privately instead.

For additional context, see the official PHP mysql_query documentation.

Step 4: Replace mysql_fetch_assoc() With MySQLi

Checking mysql_query() fixes the immediate warning on old PHP installations.

However, it's not a suitable long-term solution because the entire mysql_* API has been removed.

For modern PHP, migrate to MySQLi or PDO.

Here's the same working example using MySQLi.

Create users-mysqli.php:

<?php

mysqli_report(
    MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT
);

try {
    $db = new mysqli(
        '127.0.0.1',
        'root',
        '',
        'fetch_demo'
    );

    $db->set_charset('utf8mb4');

    $result = $db->query(
        'SELECT id, name FROM demo_users ORDER BY id'
    );

    echo 'Total users: ' . $result->num_rows . PHP_EOL;

    while ($row = $result->fetch_assoc()) {
        echo $row['id'] . ': ' . $row['name'] . PHP_EOL;
    }

    $result->free();
    $db->close();

} catch (mysqli_sql_exception $e) {
    error_log($e->getMessage());
    exit("Database operation failed.\n");
}

Run it:

php users-mysqli.php

This example assumes a local MySQL installation using the root account with an empty password, as is common in some local XAMPP setups. Change the connection details to match your installation. Never use an unrestricted root account for a production website.

Expected output for the initial sample data:

Total users: 2
1: Amina
2: Ravi

Why is this approach better?

Modern MySQLi returns a mysqli_result object for successful SELECT queries, rather than the old mysql_* resource.

Its equivalent methods include:

$result->fetch_assoc();
$result->fetch_array();
$result->fetch_row();
$result->num_rows;

The example explicitly enables exception-based MySQLi error reporting.

When the query fails, execution moves to the exception handler instead of continuing into the fetch loop.

This is standard practice. The PHP MySQLi documentation also explains the reporting behavior.

One important variation: statements such as INSERT, UPDATE, and DELETE do not return a SELECT result set. Calling a fetch method on their boolean success result is incorrect.

Step 5: Use PDO Prepared Statements for User-Supplied Values

MySQLi works well, but PDO is another widely used approach.

PDO becomes particularly useful when a query contains values supplied by a user.

Suppose we want to fetch users whose IDs are greater than or equal to a requested value.

Create users-pdo.php:

<?php

try {
    $pdo = new PDO(
        'mysql:host=127.0.0.1;dbname=fetch_demo;charset=utf8mb4',
        'root',
        '',
        [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
        ]
    );

    $minimumId = 1;

    $statement = $pdo->prepare(
        'SELECT id, name
         FROM demo_users
         WHERE id >= :minimum_id
         ORDER BY id'
    );

    $statement->bindValue(
        ':minimum_id',
        $minimumId,
        PDO::PARAM_INT
    );

    $statement->execute();

    while ($row = $statement->fetch()) {
        echo $row['id'] . ': ' . $row['name'] . PHP_EOL;
    }

} catch (PDOException $e) {
    error_log($e->getMessage());
    exit("Database operation failed.\n");
}

Run:

php users-pdo.php

Expected result: The script prints the matching user records.

PDO prepared statements keep user-provided values separate from SQL syntax, helping prevent SQL injection.

With exception mode enabled, query failures produce PDOException rather than silently returning an invalid result.

You'll need the pdo_mysql PHP extension enabled.

The official PDO prepared statements documentation explains parameter binding in detail.

Step 6: Check Other Causes of Resource and Fetch Errors

Several similar-looking errors require slightly different solutions.

A query returns no matching records

This is normal:

$result = $db->query(
    'SELECT id, name FROM demo_users WHERE id = -1'
);

if ($result->num_rows === 0) {
    echo 'No users found.';
}

An empty SELECT result isn't a failed query.

The connection and result variables are mixed up

Incorrect:

$row = mysqli_fetch_assoc($db);

Correct:

$result = $db->query(
    'SELECT id, name FROM demo_users'
);

$row = mysqli_fetch_assoc($result);

$db is the connection; $result is the SELECT result object.

PHP says "Call to undefined function mysql_query()"

This means the old MySQL extension isn't available.

Changing mysql_fetch_array() alone won't fix it. Migrate the connection, query, and fetch functions together.

MySQLi throws mysqli_sql_exception

This is the modern equivalent of discovering that a query failed.

Read the exception in your server logs, check the SQL statement, and correct the actual database error.

mysql_num_rows() is used after INSERT

An INSERT does not produce a SELECT result set.

With MySQLi, use the connection's affected-row information when you need to know how many records were changed.

For example:

$db->query(
    "UPDATE demo_users SET name = 'Amina'
     WHERE id = 1"
);

echo $db->affected_rows;

The value represents affected rows, not the number of rows available to fetch.

Quick Verification: Confirm the MySQL Fix

Run the MySQLi example again:

php users-mysqli.php

You should see the total number of records and their IDs and names without any fetch-related warning.

Then temporarily change demo_users to missing_users in the query and rerun the script.

Expected result: The script should log a database error and show the generic failure message, rather than attempting to fetch from an invalid result.

Restore the correct table name afterward.

This verifies both the successful query path and the error-handling path.

Next Steps: Remove the Remaining Legacy MySQL Calls

Search your project for mysql_query, mysql_fetch_array, mysql_fetch_assoc, mysql_fetch_row, and mysql_num_rows. Migrate the connected code to either MySQLi or PDO, use prepared statements whenever a query contains external input, and test both successful and failing queries. The lasting fix isn't suppressing the warning; it's ensuring database errors are handled before any fetch operation runs.

More MySQL articles