Main

Home Assistant Slows Down After Six Months: Recorder Retention, Database Bloat, and a Purge You Can Measure

The “six months” story is folk wisdom, not a documented mechanism. Home Assistant’s recorder documentation describes continuous recording and default purge/repack behavior, but it does not claim that a specific elapsed time causes slowdown. What the docs do support is a measurable maintenance task: read your own recorder database size, tune the documented knobs, purge, repack, and re-measure. That is the version of this topic worth acting on.

What the recorder actually does

The Recorder integration is enabled by default as a dependency of the History integration, and it constantly saves data to the media Home Assistant is installed on. Every time an entity changes state — a light turning on, a sensor reporting a new temperature, a door opening — the recorder writes that change to a database. It also stores events. History and Activity panels, dashboard graphs, and long-term statistics all read from that database. Without the recorder, Home Assistant would still show current states, but it would not keep history for those features. Home Assistant Recorder documentation

On a default install, that database is SQLite, stored in the configuration directory as home-assistant_v2.db. The docs note that this constant writing can affect system reaction time and the life expectancy of an SD card on a Raspberry Pi, and recommend either raising commit_interval, limiting stored data through excludes, or moving the database elsewhere. That is the documented pressure. It is not a countdown clock.

Measure your own database before assuming a cause

Before changing anything, get a number. The SQL integration can populate a sensor from an SQL database, and it defaults to the recorder’s db_url if none is specified. The docs provide engine-specific queries for database size. Home Assistant SQL integration documentation

For SQLite, the documented query is:

SELECT ROUND(page_count * page_size / 1024 / 1024, 1) as size
FROM pragma_page_count(), pragma_page_size();

Use size as the column. The returned unit is MiB; set the device class to Data size so the UI can convert units.

For MariaDB or MySQL, the documented query is:

SELECT table_schema "database",
  Round(Sum(data_length + index_length) / POWER(1024, 2), 1) "value"
FROM information_schema.tables
WHERE table_schema = "homeassistant"
GROUP BY table_schema;

Replace homeassistant with your database name. Use value as the column.

For PostgreSQL:

SELECT pg_database_size('dsmrreader') / 1024 / 1024 as db_size;

Replace dsmrreader with the correct database name. Use db_size as the column.

By default the SQL integration polls every 30 seconds. If you want a different interval, disable polling in the integration’s system options and create an automation that calls homeassistant.update_entity. That action has a 10-second debounce, so entities cannot update more frequently than once every ten seconds through this method.

Write the number down. That is your baseline.

The defaults that govern growth

Four recorder settings determine how much data accumulates and how often it is cleaned up. All defaults below are from the recorder documentation.

  • auto_purge defaults to true and purges the database every night at 04:12 local time. The docs state that purging keeps the database from growing indefinitely, which takes up disk space and can make Home Assistant slow.
  • auto_repack defaults to true and repacks the database on the second Sunday of each month, after the auto purge. Without a repack, the database may not decrease in size even after purging. This flag has no effect if auto_purge is disabled.
  • purge_keep_days defaults to 10 and specifies the number of history days to keep in the recorder database after a purge.
  • commit_interval defaults to 5 seconds. Increasing it reduces disk I/O and may prolong disk (SD card) lifetime, with the trade-off that the database will lag. Activity and history do not lag, because changes are streamed to them immediately. Setting it to 0 commits as soon as possible after an event is processed.

If you disable auto_purge, the docs recommend creating an automation to call recorder.purge periodically. If you disable auto_repack, the same recommendation applies.

Why purge alone may not shrink the file

This is the part that trips people up. The docs state plainly that without a repack, the database may not decrease in size even after purging. A reader who lowers purge_keep_days, triggers a purge, and sees the file size unchanged may conclude the fix failed. It did not fail; the file just has not been repacked yet.

Pairing purge with repack is the documented way to actually reduce file size. The monthly auto_repack handles this on the second Sunday. If you want to see the effect sooner, you can trigger a purge with repack enabled, or wait for the scheduled repack.

Filters: stop writing what you do not need

By default, no entity is excluded from recording. The recorder supports include and exclude maps with domains, entity_globs, entities, and event_types lists. The docs give the example of excluding often-logged events like sensor.last_boot to reduce storage and keep the database small.

Filter application follows a documented order. With no filter, all entities are included. With only includes, an entity is included if it is listed in entities, matches a domain include, or matches a glob include; otherwise it is excluded. With only excludes, an entity is excluded if it is listed in exclude, matches a domain exclude, or matches a glob exclude; otherwise it is included. Domain and/or glob includes may also have excludes, and the docs lay out the precedence in detail.

Entity globs support * for zero, one, or multiple characters and ? for zero or one character. A common pattern is to include the sensor domain but exclude specific noisy sensors with entity_globs.

If you only want to hide events from the Activity panel, the docs point to the Activity integration. If you have privacy concerns or want events in neither history nor activity, use the recorder’s exclude/include options so they are not written to the database at all.

A repeatable procedure

This is a measurement loop, not a claim about a timeline.

  1. Record the baseline. Add an SQL sensor using the query for your database engine. Note the value.
  2. Adjust the knobs. Consider lowering purge_keep_days, raising commit_interval, and adding exclude filters for entities you do not need in history. Each change is a tradeoff: shorter retention means less history; higher commit interval means the database lags; excludes mean those entities have no history or statistics.
  3. Restart Home Assistant to apply configuration changes.
  4. Call recorder.purge. The recorder provides actions including recorder.purge (cleans up old data), recorder.purge_entities (removes recorded data for specific entities, domains, or patterns), recorder.disable, recorder.enable, and recorder.get_statistics.
  5. Confirm a repack ran. Auto_repack runs on the second Sunday of each month. If you need it sooner, trigger it explicitly. Without a repack, the file may not shrink.
  6. Re-read the SQL sensor and compare to the baseline.

If the number did not move, check whether a repack actually ran before concluding the change had no effect.

Disk-space safety rules

The docs state a bare minimum requirement: have at least as much free temporary space available as the size of your database at all times. A table rebuild, repair, or repack may happen at any time, which can result in a copy of the data on disk during the operation. For example, if your database is 1.5 GiB on disk, you must always have at least 1.5 GiB free.

For SQLite specifically, if the system encounters unrecoverable disk corruption, it will move the database aside and create a new database to keep the system online. In that case, having at least 2.5x the database size available in free disk space is essential. Starting a new database is the system’s last resort recovery option and is usually caused by failing flash storage, an inadequate power supply, an unclean shutdown, or another hardware failure.

This is the graceful-degradation signal worth monitoring. If your recorder database is the largest persistent artifact on the host, watching its size gives you a warning before disk pressure forces a corruption-driven reset.

What not to do

Changing the database used by the recorder may result in losing your existing history. Migrating data is not supported. The docs also warn that SQLite is the most tested engine and that newer versions of Home Assistant are highly optimized to perform well with it. If you are considering MariaDB, MySQL, or PostgreSQL, you should be comfortable acting as the database administrator, including making backups of the external database. The docs note that MariaDB versions before 10.5.17, 10.6.9, 10.7.5, and 10.8.4 suffer from a performance regression that can overload the system while querying history or purging.

If your recorder database is small and your system is responsive, the honest answer may be that no maintenance is needed. A plain switch or a mechanical timer is sometimes the smarter choice for a specific device, and the same logic applies here: if the measurement does not show a problem, the fix is not required.

FAQ

Does Home Assistant actually slow down after six months?

The documentation does not state a timeline or a causal link between elapsed time and slowdown. It does state that purging keeps the database from growing indefinitely, which takes up disk space and can make Home Assistant slow. The measurable version of this concern is database size, not calendar age.

Why did my database not shrink after I purged?

Without a repack, the database may not decrease in size even after purging. Auto_repack runs on the second Sunday of each month. If you need the size reduction sooner, trigger a repack.

Can I just delete the database file?

The docs describe a specific corruption-recovery behavior: if SQLite encounters unrecoverable disk corruption, it moves the database aside and creates a new one. Manually deleting the file is not the documented procedure and will lose history. If you want to start fresh, the documented path is to let the system handle corruption recovery or to change the database configuration, understanding that migration is not supported.

Should I switch to MariaDB or PostgreSQL for better performance?

The docs warn that SQLite is the most tested and that newer Home Assistant versions are optimized for it. They also note that changing the database may lose existing history and that migration is not supported. If you switch, you take on the role of database administrator. For most residential and small-office installs, the documented defaults plus measurement are the lower-risk path.

How do I know if my recorder database is too big?

There is no documented threshold. The practical check is free disk space relative to database size. The docs require at least as much free temporary space as the database size at all times, and 2.5x the database size for SQLite corruption recovery. If free space is approaching those margins, it is time to act.

What is the difference between recorder.purge and recorder.purge_entities?

recorder.purge cleans up old data from the recorder database. recorder.purge_entities removes recorded data for specific entities, domains, or patterns. Both are documented recorder actions.

For a broader look at auditing the small systems that quietly run your week, see How to Audit the Small Systems That Quietly Run Your Week.