diff --git a/changelog.d/sqlite-prepare-cached.changed b/changelog.d/sqlite-prepare-cached.changed
new file mode 100644
index 00000000000..7164cdb3274
--- /dev/null
+++ b/changelog.d/sqlite-prepare-cached.changed
@@ -0,0 +1,2 @@
+Cache prepared statements on hot SQLite read paths (Clarity side-store reads, MARF block-id/hash lookups, and the generic `query_*` helpers) instead of re-parsing the SQL on every call, and raise the per-connection statement-cache capacity so the cache is not LRU-thrashed
+
diff --git a/clarity/src/vm/database/sqlite.rs b/clarity/src/vm/database/sqlite.rs
index 0094d8e95d2..bc38a21a62f 100644
--- a/clarity/src/vm/database/sqlite.rs
+++ b/clarity/src/vm/database/sqlite.rs
@@ -54,7 +54,10 @@ pub struct SqliteConnection {
fn sqlite_put(conn: &Connection, key: &str, value: &str) -> Result<(), VmExecutionError> {
let params = params![key, value];
- match conn.execute("REPLACE INTO data_table (key, value) VALUES (?, ?)", params) {
+ match conn
+ .prepare_cached("REPLACE INTO data_table (key, value) VALUES (?, ?)")
+ .and_then(|mut stmt| stmt.execute(params))
+ {
Ok(_) => Ok(()),
Err(e) => {
error!("Failed to insert/replace ({key},{value}): {e:?}");
@@ -67,11 +70,8 @@ fn sqlite_get(conn: &Connection, key: &str) -> Result