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:
- the exact database error,
- hosting database logs,
- connection limits,
- concurrent PHP/AJAX requests,
- 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.