When EspoCRM slows down as the database grows
Performance tuning is a diagnosis-first exercise that covers three layers: server resources, database settings and the way people use the system. When list views, filters and reports take longer as records accumulate, the fix is rarely a single setting. Start by finding out which layer is the bottleneck, then change one thing at a time and measure again. EspoCRM's documented requirements set the baseline: PHP 8.3 to 8.5, MySQL 8.0 or newer, or MariaDB 10.6 or newer, or PostgreSQL 15, served by Apache, Nginx or IIS. Meeting that baseline makes the platform supported, but it does not decide how fast your instance responds. That depends on what sits above the baseline, including how much data you hold, how many users query it at once and how heavily your customizations hit the database.
Confirm the current versions of PHP, your database and your web server against the EspoCRM server configuration docs before you touch anything else, since an unsupported combination can explain slowness by itself. Then establish a baseline: note which list views, filters and reports are slow, who uses them, and how long they take at quiet and busy times. Your database and web server logs, along with the EspoCRM logs, will show whether the time goes to the database, to PHP or to the network. Keep in mind that exact gains depend on your hardware, data volume, customizations and workload, so no tuning guide can promise a specific improvement. Ask any partner or internal team to show measurements from your environment before and after each change.
Once you know where the time goes, the decisions become concrete: how much memory the server gives the database, whether your heaviest filters need a different database engine, and which list view and report habits add load for no business value. Each of these has its own trade-offs, and the sections that follow work through them. Plan for the change to be ongoing, because a growing instance adds records and customizations that shift the bottleneck over time. Record the settings you change and the measurements behind them, so the next person who investigates a slowdown can tell what was already tried.
Which tuning lever fits which bottleneck
Slowness that affects every page, including simple record views and the login screen, usually starts at the web or PHP layer. When the database is idle but requests queue up, the application server is often waiting on workers, memory, or the file system rather than on SQL. EspoCRM runs on Apache, Nginx or IIS with PHP 8.3 to 8.5 according to its server configuration docs, so the first checks belong to that stack.
- PHP worker capacity: Look for requests that wait before execution starts. Confirm the PHP-FPM or equivalent pool size against the number of concurrent users, and check whether the pool is saturated during peak hours.
- PHP memory and execution limits: Large list exports and report generation hit these limits first. Errors in the PHP error log point to the exact limit to raise.
- OPcache configuration: Confirm that bytecode caching is enabled and sized for the EspoCRM codebase and any custom extensions.
- Static asset and proxy settings: Check whether the reverse proxy serves static files efficiently and whether timeouts for long requests match what users run.
- Host resources: Review CPU steal, memory pressure and disk latency on the host or virtual machine.
Check first: whether slowness is uniform across pages and whether PHP pool saturation or PHP error logs show queued or failed requests. Ask your platform team to confirm these values in your environment before changing them.
Slowness that appears on specific list views, filters, sorts or reports, while simple record pages stay fast, usually points to the database. EspoCRM supports MySQL 8.0 or newer, MariaDB 10.6 or newer, or PostgreSQL 15 according to its server configuration docs, so tuning starts with the engine your team has chosen. Database tuning is most effective after you have identified which queries are slow, because buffer and sort settings only help queries that spill to disk or re-read the same data.
- Buffer pool or cache sizing: For MariaDB, check whether the InnoDB buffer pool holds the working set. Frequent disk reads on repeated queries suggest it is undersized relative to data and indexes.
- Sort and join buffers: Temporary tables written to disk during sorts and joins point to sort buffer settings or missing indexes. Raising buffers globally can consume memory quickly, so confirm per-connection costs first.
- Slow query log: Enable it briefly to capture the actual statements behind slow views and reports.
- Index coverage: Compare slow filter and sort columns with existing indexes. Index work is covered separately, but the query plan shows where to start.
- Engine choice for heavy filters: Compare how the chosen engine handles your largest filtered reports before you consider changing it, and confirm the EspoCRM version supports the engine and version you plan to use.
Check first: the slow query log and the execution plans for the top few slow statements. Ask your database administrator to confirm parameter values against your data volume and memory budget.
Some slowness comes from how EspoCRM is set up and used rather than from the servers under it. Heavy list views with many columns, wide relationship joins, reports built on large unfiltered sets, and background jobs that run too rarely can all look like infrastructure problems. Changing the habit or configuration is often cheaper than adding hardware, and it should be checked before capacity is bought.
- List view design: Long default lists with many linked fields and computed columns force joins on every page load. Trim columns and default filters to what teams use.
- Default sort and filter fields: Sorting on unindexed fields across a large entity is a common source of slow list loads.
- Report scope: Reports without date ranges or owner filters scan the whole entity. Teams should scope reports and schedule heavy ones off-peak.
- Background job backlog: Queued jobs that never finish can slow the system and delay workflows. Check the scheduled job state and whether cron or the daemon keeps pace.
- Customization load: Before-save formula scripts and workflows that run on every save add work to bulk updates and imports.
Check first: which views, reports and saved filters the complaining users open most often, and whether any of them can be narrowed without losing business value.
Performance options and when each fits
This table compares the main ways to speed up a large EspoCRM instance, from hardware and database tuning to changing database engines and trimming list views and reports. Read each row for the situation where it fits and the trade-off it brings, then confirm current settings against the server configuration docs before changing anything.
| Option | When it fits | Main trade-off | What to confirm first |
|---|---|---|---|
| Add CPU and RAM to the application and database server | Slow pages across the board on an instance that is otherwise well indexed and whose database fits in memory | Recurring hosting cost, and it does not fix slow queries caused by unindexed filters or wide list views | Current CPU, memory and database size during peak use |
| Raise the MariaDB InnoDB buffer pool | Database reads dominate and the working set of records and indexes does not fit in memory | Memory is taken from PHP and the operating system, so an oversized pool can cause swapping | The buffer pool value relative to total memory and the data size in your database |
| Adjust sort and join buffers | Specific list views or reports sort or join large result sets and show temporary table or sort pressure | Per-connection memory multiplies with concurrent users, so large values can exhaust RAM quickly | Recommended values in the MariaDB documentation and the EspoCRM server configuration docs for your version |
| Move to PostgreSQL for heavy filtering | Your team runs many complex, multi-field filters and reports that remain slow after indexing and buffer tuning | A migration project with testing, re-validation of customizations and extensions, and a database team skill set to maintain | Supported database versions in the EspoCRM server configuration docs and whether your extensions support PostgreSQL |
| Schedule reports and heavy jobs off-peak | Reports, mass updates or imports cause slowdowns during working hours but are not needed in real time | Results arrive later, and off-peak windows need monitoring so jobs do not overlap | Which jobs run through cron or the daemon and their scheduled times in the admin panel |
| Narrow default list columns and filters | Users open list views that load many fields, joins or unfiltered records by default | Some users may need to add columns manually, and layouts need ongoing review as fields change | Which list views and saved filters are used most and which fields they load |
| Trim report scope and saved filters | Reports join many entities or scan full tables to answer questions a narrower date or owner filter would answer | Reports may show less history unless users are told how to widen the scope | Report definitions and the query plans they produce on your database |
How to run a tuning pass on a live EspoCRM
This sequence turns vague complaints about a slow EspoCRM into a measured, reversible tuning pass, where each change is tied to a baseline and confirmed by re-measurement. It protects production data and keeps the team able to explain what changed and why.
Capture a baseline of slow pages
Before touching anything, record which list views, detail pages, reports and background jobs are slow, and when they are slow. Ask several users in different teams to name their worst screens, then time those same screens during a normal working period and during a peak. Note the record counts, the filters applied and the user roles involved, because a slow list for an administrator may be fast for a restricted user. Done means you have a written table of screens, timings and conditions that someone else on the team could repeat.
Take a verified backup
Create a full backup of the database and the EspoCRM files before any configuration or schema change, following the backup procedure your team uses for this instance. Confirm that the database dump is complete and readable, and if you run the Docker-based stack, confirm that the volumes holding data are included. Done means a restore has been tested on a separate host or that your team has a documented restore path it trusts. Tuning changes that touch indexes or rebuilds are much easier to reverse with a known-good copy in hand.
Check server and PHP settings
Compare the web server, PHP version, PHP memory and execution limits, and the database version against the EspoCRM server configuration documentation. Confirm that the PHP version falls within the range the docs list for your release and that the database is MySQL 8.0 or newer, MariaDB 10.6 or newer, or PostgreSQL 15. Check that background jobs run through cron or a scheduled task, because a backlog of queued jobs can look like a slow interface. Done means you have a list of mismatches or confirmed matches, with the exact version values recorded.
Review MariaDB memory and slow query output
Inspect the InnoDB buffer pool size, the sort and join buffer settings, and the slow query log for the statements your baseline screens generate. Ask the database administrator to confirm how much memory the host has available for the database alongside PHP and the web server, since an oversized buffer pool can starve other services. Identify the queries that dominate total time and check whether they sort or filter on columns without a suitable index. Done means you have a short list of candidate queries and a memory budget your team agrees with, but no value is changed yet.
Review list views and reports
Examine the slow list views and reports for habits that add cost: many columns from related entities, filters on computed or text fields, very wide default sorting, large page sizes, joined panels that pull in extra tables, and reports run on the full dataset when a narrower date range would answer the question. Note which customizations added these joins, since the same layouts may be shared by many users. Done means each slow screen has a documented cause or a stated unknown, and you can say which changes are about layout and which are about data.
Change one variable at a time
Apply a single change from your candidate list, such as one buffer setting, one index or one simplified list layout, and record the before and after values. Make the change in a test or staging copy first where possible, then in production during a window your team has agreed with its users. Avoid bundling a server upgrade with a schema change, since you will not know which one helped or harmed. Done means a dated change record exists that names the variable, the old value, the new value and the person who approved it.
Re-measure against the baseline
Repeat the same timed screens and the same slow queries under the same conditions you used for the baseline, and compare the results row by row. Confirm that the change did not slow other screens, that users with restricted roles still see correct data, and that background jobs are still completing. If the change helped, keep it and move to the next candidate. If it did not, or it caused a regression, roll it back using the change record and the backup. Done means every change has a verdict recorded against the baseline.
When MariaDB tuning is not enough for heavy filters
Tuning MariaDB is the right first step for most growing EspoCRM instances, but there is a point where further buffer pool or sort buffer changes stop helping. The deciding signal is the shape of your queries, not the number of records. A database with millions of contacts can run well if most list views filter on indexed fields with few joins, while a smaller instance can struggle when users combine several custom relationship filters across many related entities. Before weighing a database change, capture the slowest list views, reports and scheduled jobs, record their filter and join patterns, and check the query plans for them on your current MariaDB or MySQL version. If the slow queries share the same missing indexes or the same heavy joins, that points to schema and index work first.
Switching to PostgreSQL 15 is a supported option on the EspoCRM server configuration list, alongside MySQL 8.0 or newer and MariaDB 10.6 or newer, but it is a migration, not a setting change. Confirm the exact supported versions for your target release in the EspoCRM server configuration docs before you commit. Ask your team to document which custom fields, formulas and reports depend on database-specific behavior, and to confirm with EspoCRM which schema and rebuild steps apply when the platform is installed on PostgreSQL. Expect the work to include data export and import, a full rebuild, re-running indexing checks and retesting every workflow and scheduled job, and the cost of that work depends on how heavily your instance has been customized.
Validate the choice in a test copy built from a recent backup on production-equivalent hardware. Measure the same list views, reports and job runs before and after, and keep the source MariaDB instance untouched and writable until cutover is signed off. Write a rollback plan that states who decides to revert, how long the source remains available, and how data written during the test window is reconciled. Treat the database move as a separate change from any PHP or EspoCRM version upgrade so that a failure can be traced to one cause.
Which list view and report habits slow EspoCRM down
Most slow EspoCRM instances are not short of hardware. They are asked to sort, filter and join far more data than a list view or report needs. The six habits below are the usual sources of that load, and each one has a fix that the sibling topics on indexes and reports cover in detail. Check them before you buy a bigger database server.
Wide default list columns
Every column in a list view is a field the server must select and, often, join. A default list layout that shows a dozen related fields from linked records multiplies the work on every page load. Review the list layouts for the most-used entities and keep the default view to the fields people scan before they open a record. Move detail fields into the record view, where they load only for one item. Ask your team which columns they actually read each day.
Filters on unindexed fields
A filter or default sort on a field with no database index forces the database to scan every row of the entity. The cost grows with the table, so a filter that feels instant on 5,000 contacts can stall on several million. Identify the filters and sort orders your sales and service teams use most, then add indexes for those fields. Confirm with your database's slow query log which queries are slow before you add anything, because every index also slows writes.
Reports joining many entities
Reports that join several related entities, or that group across large tables, ask the database for a large intermediate result before any filter narrows it. Each extra join adds work, and a report built over many customizations can hit the database limit on joined tables. Keep reports to the entities they need, filter on the primary entity first, and schedule heavy reports outside peak hours. Follow the sibling topic on reports for the report types and their trade-offs.
Unbounded result sets
Lists and exports that return every matching record in one request push memory and network load onto both PHP and the database. Users rarely need more than the first page, but a saved list, a mass action or an export can pull the whole table. Keep page sizes reasonable, encourage filters before export, and check which API integrations request large collections without paging. Ask each integration owner how many records a single call returns.
Heavy before-save formula scripts
Formula Script runs in before-save hooks, API before-save scripts, workflows and BPM, so a slow formula runs on every save of the entity it belongs to. A script that loads related records, loops over linked collections or runs many lookups adds that cost to each create and update, including bulk updates. Review before-save scripts on high-volume entities, move work that does not need to run on every save into scheduled or workflow steps, and test the change on a copy of production data.
Large imports run during business hours
A CSV import of hundreds of thousands of rows creates, updates and matches records in bulk, which competes with interactive users for database connections and locks. EspoCRM's import supports idle execution through cron for large files, which keeps the work in the background. Schedule large imports for off-hours, run them in idle mode, and check import progress and reverting options before you start. Confirm the import mode and duplicate matching fields with your data owner first, because a wrong match rule multiplies the cleanup.
Questions buyers ask about EspoCRM performance tuning
What drives the cost of an EspoCRM performance tuning engagement?
The main driver is how much of the system has to be examined and how many changes follow from that examination. Cost rises with the number of slow screens, the size and shape of the database, the amount of custom fields, layouts and formula logic involved, and how many environments must be checked. Part of the fee is one-time analysis and tuning work. Part may recur if you later want a retainer for monitoring or a second pass after upgrades. DeployOpen works on fixed scope agreed in writing before work starts, so ask for the quote to list the analysis, the changes, the test steps and what you receive at handover, along with which items are optional.
How long does a tuning pass take, and what sets that duration?
The duration depends on the scope agreed in writing, not on a fixed template. The biggest factors are the number of slow list views, reports and workflows, how much custom schema has been added, whether the work needs a test copy of production data, and how quickly your change window and approvals move. A pass that only reviews server settings and a few queries is shorter than one that also reworks indexes, reports and database engine choices. Ask the proposal to show the phases, the points where you must approve changes, and the dependencies on your team's availability.
What must our team provide before a tuning engagement starts?
Plan to provide access and information that lets the work be measured rather than guessed. Typical items include:
- Administrative access to the server, PHP and database configuration, and the EspoCRM instance
- Web server, PHP-FPM, MariaDB or MySQL and EspoCRM logs covering slow periods
- A test copy of the database and files that matches production closely enough to reproduce slow screens
- A description of usage patterns: peak hours, typical filters, sort orders, report runs and mass actions
- A list of custom entities, formulas, workflows and extensions in use
Data copies may contain personal data, so confirm handling rules with your data protection owner before sharing anything.
Can an in-house EspoCRM administrator tune performance without outside help?
Often yes for basic work. An experienced administrator can review cron or daemon job load, check the web server and PHP settings, read slow query output and remove unnecessary list columns or heavy filters. Deeper work usually needs database engineering skill: sizing the MariaDB buffer pool and sort buffers, reading execution plans, designing indexes safely and testing rebuilds. Rebuilds and schema changes should be preceded by a backup and tested on a copy. If your team lacks time or database depth, a fixed-scope engagement can cover that part while your administrators keep ownership of the running system.
When is a database migration to another engine justified?
Consider a move only after tuning the current setup shows that the database engine is the limiting factor. EspoCRM's server configuration documents support MySQL 8.0 or newer, MariaDB 10.6 or newer, or PostgreSQL 15, so the choice is supported but should be tested for your workload. Heavy multi-field filters, complex reports and large joins are the usual cases to benchmark. Also weigh the cost of migration, the effort of retesting customizations and the operational skills your team already has. Verify version requirements against the current documentation before you decide.
Is self-hosted tuning cheaper than using EspoCRM Cloud?
It depends on what you already run and what you need to control. EspoCRM's pricing page lists Cloud plans at 15 US dollars per user per month on Basic (minimum 3 users), 25 dollars on Enterprise (minimum 5 users) and 69 dollars on Ultimate (minimum 10 users), with the Advanced Pack included in all cloud plans. Self-hosting lets you set the server, database and data residency, but the infrastructure, patching, backups and tuning work become your responsibility. Compare the recurring cloud subscription with your own hosting, staffing and support costs over the same period.
How is a fixed-scope tuning engagement agreed in writing?
DeployOpen agrees scope, deliverables and timelines in writing before work starts. The written scope should name the systems covered, the performance symptoms in focus, the environments involved, the changes you approve, the testing evidence you receive and the acceptance criteria. Ask that it also state what is excluded, such as application code changes or hardware purchases, and how change requests are priced if the findings expand the work. Ongoing support, upgrades and continuous testing are available as retainers and can be scoped separately.
How DeployOpen scopes and delivers EspoCRM tuning
DeployOpen plans and implements EspoCRM performance work inside your own infrastructure, starting from measured slow views and reports rather than guesses. Engagements are fixed-scope, so the tuning targets, deliverables and handover are agreed in writing before any server or database setting changes.
How we scope
- Inventory the EspoCRM version, PHP and database versions, server layout and the slowest list views and reports.
- Agree which database, server and customization changes are in scope, with each deliverable named in writing.
- Confirm the change window, backup requirements and who approves production changes before work starts.
How we build
- Measure current response times and slow queries on a copy of the instance before adjusting any setting.
- Test MariaDB buffer pool and sort buffer changes, index additions and list view adjustments in a staging environment.
- Review customizations that add joined tables or heavy filters, and document each change with its measured effect.
How we hand over
- Deliver a written record of every configuration change, index, and rollback step, with the original values kept.
- Walk your administrators through the monitoring checks and the habits that keep list views and reports fast.
- Provide a short runbook for repeating measurements after your own data growth or EspoCRM upgrades.
How we support
- Offer ongoing support, upgrades and re-tuning as a retainer when your data volume or user count changes.
- Re-measure performance after EspoCRM upgrades, since query plans and indexes can change between versions.
- Confirm with your team which support hours, response paths and review cadence fit your operating model.

