Fixing Intermittent OpenCart Database Connection Errors on Hostinger with Persistent MySQL Connections

The Problem: OpenCart Randomly Loses Its Database Connection

We recently investigated an interesting OpenCart issue on a live store hosted with Hostinger.

The customer reported that the checkout page would occasionally display errors similar to:

Exception: Error: Could not make a database link using username@localhost!
File: system/library/db/mysqli.php

The unusual part was that the problem was intermittent.

The checkout might fail immediately after loading or refreshing the page, but clicking another delivery method or selecting an option such as:

My delivery and billing addresses are the same

would cause the checkout to refresh and suddenly work correctly.

Refreshing the entire browser page could then cause the database errors to return.

The customer also tested the website in an incognito/private browser window, confirming that this was not simply a browser cache or cookie problem.

Even more confusingly, OpenCart’s:

System → Maintenance → Error Logs

contained no corresponding errors.

However, Hostinger’s server-side logs showed repeated database connection failures at exactly the same period that the checkout problems were occurring.

This gave us an important clue.


The Error Was Not Actually a Checkout Error

At first glance, because the problem appeared inside the checkout, it would be reasonable to suspect:

  • a shipping extension
  • a payment extension
  • a checkout modification
  • an OpenCart OCMOD conflict
  • JavaScript
  • the theme
  • a one-page checkout extension

But the actual error was occurring much earlier.

When OpenCart displays an error from:

system/library/db/mysqli.php

saying that it could not make a database connection, OpenCart has failed while attempting to establish its MySQL connection.

This happens during the OpenCart bootstrap/startup process.

In other words, the affected request may not have reached the shipping, payment or checkout logic at all.

The application simply could not establish a database connection for that particular PHP request.


Why Would It Work One Second and Fail the Next?

This is where Hostinger’s MySQL connection limits become important.

Hostinger currently limits the number of new MySQL connections that an account can create within a short period.

A PHP application such as OpenCart commonly creates a database connection whenever a new PHP request starts.

For a traditional page this may not seem significant:

Browser Request
      ↓
PHP starts
      ↓
OpenCart starts
      ↓
MySQL connection created
      ↓
Page generated

But a modern ecommerce checkout may generate several PHP requests almost simultaneously.

For example:

Checkout page request
Shipping method request
Payment method request
Address request
Cart totals request
Session request
Custom extension AJAX request

Each PHP request may initialise OpenCart independently.

And each one may therefore create another MySQL connection.

Now add:

  • another customer browsing the store
  • Google or another search crawler
  • monitoring bots
  • admin activity
  • cron jobs
  • API requests
  • other AJAX functionality
  • another website hosted under the same hosting account

and a relatively small number of visitors can suddenly generate a burst of new database connections.


Why Checkout Pages Are Particularly Good at Triggering It

Checkout pages tend to be much more dynamic than ordinary category or product pages.

Many OpenCart checkout implementations make AJAX requests when:

  • the checkout initially loads
  • the customer changes their country
  • the postcode changes
  • the shipping address changes
  • the billing address changes
  • the customer selects a shipping method
  • the payment method changes
  • totals need recalculating
  • coupons or vouchers are applied
  • the cart changes

A one-page checkout extension can generate even more simultaneous requests.

This explains the unusual behaviour we observed.

Initial page refresh

A full checkout refresh could trigger several requests together:

Request 1 ─┐
Request 2 ─┤
Request 3 ─┤
Request 4 ─┤──► New MySQL connections
Request 5 ─┤
Request 6 ─┘

If enough other connections were being made at the same time, some requests could fail.

A few seconds later

The customer clicks another shipping method.

Only one or two AJAX requests may now be required:

Shipping Method Changed
          ↓
     AJAX request
          ↓
Database connection succeeds
          ↓
Checkout section refreshes

The checkout appears to magically repair itself.

Nothing was actually repaired by changing the shipping method.

The later request simply managed to connect successfully to MySQL.


Why OpenCart’s Error Log Can Be Completely Empty

This was another important clue in this particular case.

The customer had cleared:

System → Maintenance → Error Logs

and reproduced the checkout error.

Nothing new appeared.

This can happen because database initialisation occurs extremely early during OpenCart startup.

A typical failure may occur around:

system/library/db/mysqli.php
system/library/db.php
system/framework.php
system/startup.php

At this stage, OpenCart’s normal application logging system may not yet be fully available.

Therefore:

A blank OpenCart error log does not prove that no server or database error occurred.

Hosting-level MySQL logs can reveal problems that OpenCart itself is unable to record.

If an intermittent database connection problem is suspected, always compare the exact failure time against your hosting provider’s server/database logs.


Hostinger’s Recommended Solution: Persistent MySQL Connections

Hostinger recommends persistent database connections for websites affected by this type of connection-rate problem.

With a normal MySQLi connection, OpenCart may connect using:

localhost

MySQLi supports persistent connections by prefixing the host with:

p:

Therefore:

localhost

becomes:

p:localhost

The p: prefix tells PHP/MySQLi that the connection should be persistent.

Instead of creating a completely new database connection every time a PHP request needs one, PHP can reuse an existing connection associated with a PHP worker.

This substantially reduces the number of new MySQL connections being created during traffic or AJAX bursts.


Applying the Fix to OpenCart

Important: Back up both configuration files before making any changes.

A standard OpenCart installation normally contains two main configuration files:

/config.php

and:

/admin/config.php

Open both files.

Look for:

define('DB_HOSTNAME', 'localhost');

Change it to:

define('DB_HOSTNAME', 'p:localhost');

So the database section changes from something similar to:

define('DB_DRIVER', 'mysqli');
define('DB_HOSTNAME', 'localhost');
define('DB_USERNAME', 'your_database_user');
define('DB_PASSWORD', 'your_database_password');
define('DB_DATABASE', 'your_database_name');
define('DB_PORT', '3306');

to:

define('DB_DRIVER', 'mysqli');
define('DB_HOSTNAME', 'p:localhost');
define('DB_USERNAME', 'your_database_user');
define('DB_PASSWORD', 'your_database_password');
define('DB_DATABASE', 'your_database_name');
define('DB_PORT', '3306');

Make the same hostname change inside:

/admin/config.php

if it also contains:

define('DB_HOSTNAME', 'localhost');

The important change is simply:

- define('DB_HOSTNAME', 'localhost');
+ define('DB_HOSTNAME', 'p:localhost');

Do I Need to Refresh OpenCart Modifications?

No.

config.php and admin/config.php are normal OpenCart configuration files and are loaded directly.

Changing:

localhost

to:

p:localhost

does not normally require an OCMOD refresh.

Simply save the files and test the website.


What Does p:localhost Actually Do?

This is not an OpenCart-specific feature.

It is functionality provided by PHP’s MySQLi driver.

The prefix:

p:

requests a persistent MySQL connection.

Instead of repeatedly doing:

PHP request
↓
Create connection
↓
Query database
↓
Request finishes
↓
Connection discarded

PHP request
↓
Create another connection
↓
Query database
↓
Request finishes
↓
Connection discarded

PHP can reuse database connections:

PHP Worker
     ↓
Persistent MySQL connection
     ↓
Request
     ↓
Request
     ↓
Request

This is especially useful on hosting environments where opening large numbers of new database connections within a short time is restricted.


The Real-World Result

After identifying the connection behaviour, we changed both OpenCart configuration files from:

define('DB_HOSTNAME', 'localhost');

to:

define('DB_HOSTNAME', 'p:localhost');

The customer then tested the live store again.

The previously intermittent checkout database errors stopped occurring, and the customer confirmed that the solution resolved the issue.

This was particularly useful confirmation because the original issue could be reproduced by repeatedly refreshing the checkout page.

After enabling persistent connections, the same workflow operated correctly.


How to Test the Fix Properly

Do not test the store only once.

Intermittent issues require repeated testing.

After making the change, test the following.

1. Refresh checkout repeatedly

Open the checkout and refresh it several times.

The previous database error should no longer appear.

2. Use an incognito/private browser

This removes many browser caching variables.

Test the entire checkout again.

3. Change shipping methods

Switch between available delivery options and confirm that totals and payment methods update correctly.

4. Change billing/shipping address selections

Test options such as:

My delivery and billing addresses are the same

and confirm that the checkout updates correctly.

5. Add and remove products

Make sure cart operations continue working normally.

6. Test customer login

Login, logout and account pages should operate normally.

7. Test the OpenCart admin

Because admin/config.php has also been changed, verify:

  • admin login
  • product pages
  • orders
  • customers
  • settings
  • extension pages

8. Place a complete test order

Always perform at least one full checkout test.

Confirm:

  • order creation
  • totals
  • shipping
  • payment
  • order status
  • order emails

9. Check Hostinger’s logs again

Compare the database connection logs after the change.

Ideally the previous bursts of failed connection attempts should disappear.


Check Browser Network Activity When Diagnosing Similar Problems

Chrome or Firefox Developer Tools can help demonstrate why a checkout is producing database connection bursts.

Open:

Developer Tools → Network

and filter requests to:

Fetch/XHR

Then reload checkout.

You may see numerous AJAX requests being launched within a very short time.

Depending on the checkout implementation, they might handle:

shipping method
payment method
shipping address
payment address
cart totals
coupons
sessions
custom extension data

Each request is a separate HTTP/PHP execution and may initialise another OpenCart database connection.

If many requests occur simultaneously, persistent database connections can make a substantial difference.


What If p:localhost Does Not Fix the Problem?

A database connection error does not always mean you are hitting a connection-rate limit.

The underlying MySQL error is important.

Other causes include:

Incorrect database credentials

For example:

Access denied for user

Check:

  • DB username
  • DB password
  • database name
  • database host

A persistent connection will not fix incorrect credentials.

MySQL server unavailable

If the hosting provider’s database server is down or restarting, changing to a persistent connection may not resolve it.

Maximum concurrent connections

The hosting account may have reached a simultaneous connection limit rather than a connection-rate limit.

This needs to be checked with the hosting provider.

Hosting resource exhaustion

CPU, RAM, PHP workers, processes or I/O limits can indirectly cause application problems.

Check the hosting resource graphs around the exact time of the failure.

Broken custom code

A third-party extension may repeatedly create additional database connections instead of using OpenCart’s existing $db object.

That should be investigated separately.

Long-running database operations

Slow queries and blocked MySQL processes can also increase connection usage because existing requests remain active for longer.

Persistent connections are not a replacement for database optimisation.


Ask Hostinger for the Native MySQL Error

If Hostinger support says only:

Database connection failed

ask them for the actual MySQL error message and error number.

Useful errors might include references to:

Operation not permitted
max_user_connections
Too many connections

or another connection-specific MySQL error.

The native error provides much more useful information than OpenCart’s generic:

Could not make a database link

message.


Why This Can Suddenly Start Happening Even When Nothing Was Changed

A common question is:

“The website worked before and we haven’t changed anything. Why would this suddenly happen?”

Because the application itself does not necessarily need to change.

The number and timing of requests can change because of:

  • increased traffic
  • bots
  • crawlers
  • marketing campaigns
  • multiple customers checking out simultaneously
  • admin users working at the same time
  • cron jobs
  • API integrations
  • monitoring services
  • another website sharing the same hosting account
  • additional AJAX functionality
  • hosting-side policy or infrastructure changes

A connection-rate issue is therefore often traffic-pattern dependent, not code-change dependent.

This is exactly why it can appear random.


Persistent Connections Are Not a Universal Performance Fix

It is important not to blindly add p: to every OpenCart website.

Use it when there is evidence that database connection creation itself is causing the problem or when your hosting provider recommends persistent connections.

Persistent connections can retain database connections for longer within PHP workers.

Most normal OpenCart installations using straightforward MySQLi queries should work correctly, but stores containing highly customised database code should still be tested thoroughly.

Particular attention should be given to custom code that:

  • manually creates transactions
  • leaves transactions incomplete
  • creates temporary tables
  • changes database session settings
  • holds table locks
  • creates its own separate MySQL connections

For a standard OpenCart installation, changing DB_HOSTNAME is simple and reversible, but production testing should always be performed.


How to Roll Back

If persistent connections cause unexpected behaviour, restoring the original configuration is straightforward.

Change:

define('DB_HOSTNAME', 'p:localhost');

back to:

define('DB_HOSTNAME', 'localhost');

in both:

/config.php
/admin/config.php

No database changes are made by this modification.


Do Not Display Detailed Database Errors to Customers

One additional issue commonly discovered during this type of troubleshooting is PHP error output being enabled on a production store.

A customer should never see information such as:

database username
server paths
PHP file paths
stack traces
hosting account paths

on the storefront.

During development, detailed errors can be useful.

On a production ecommerce website, errors should be logged rather than displayed publicly.

Once troubleshooting is complete, make sure PHP/OpenCart error display settings are appropriate for production.

This is especially important on:

  • checkout
  • account pages
  • payment pages
  • admin pages

Quick Fix Summary

If your OpenCart store on Hostinger intermittently displays:

Could not make a database link

and Hostinger confirms database connection failures, check whether the website is creating too many new database connections in a short period.

For an OpenCart installation using MySQLi, Hostinger’s persistent connection solution can be applied by changing:

define('DB_HOSTNAME', 'localhost');

to:

define('DB_HOSTNAME', 'p:localhost');

in:

/config.php

and:

/admin/config.php

Then thoroughly test:

  • checkout
  • shipping
  • payment
  • cart
  • login
  • admin
  • order placement

In the real-world OpenCart case that prompted this article, the checkout was intermittently failing with database connection errors while Hostinger’s logs recorded repeated database connection failures.

After changing both OpenCart configuration files to use p:localhost, the customer retested the store and confirmed that the intermittent checkout issue was resolved.


Final Thoughts

An intermittent checkout failure does not always mean the checkout extension itself is broken.

The location of the error matters.

When OpenCart fails inside:

system/library/db/mysqli.php

before it can establish its database connection, look below the application layer.

Check:

  1. the exact database error,
  2. hosting database logs,
  3. connection limits,
  4. concurrent PHP/AJAX requests,
  5. server resource usage.

On Hostinger, persistent MySQL connections can be an effective solution when repeated new MySQL connections are the source of the problem.

The small change:

localhost

to:

p:localhost

may look insignificant, but in the right situation it can eliminate a frustrating intermittent OpenCart checkout failure that otherwise appears almost impossible to reproduce consistently.