diff --git a/extra/check-knex-filenames.mjs b/extra/check-knex-filenames.mjs
new file mode 100644
index 000000000..1cd7a8e18
--- /dev/null
+++ b/extra/check-knex-filenames.mjs
@@ -0,0 +1,70 @@
+import fs from "fs";
+const dir = "./db/knex_migrations";
+
+// Get the file list (ending with .js) from the directory
+const files = fs.readdirSync(dir).filter((file) => file !== "README.md");
+
+// They are wrong, but they had been merged, so allowed.
+const exceptionList = [
+    "2024-08-24-000-add-cache-bust.js",
+    "2024-10-1315-rabbitmq-monitor.js",
+];
+
+// Correct format: YYYY-MM-DD-HHmm-description.js
+
+for (const file of files) {
+    if (exceptionList.includes(file)) {
+        continue;
+    }
+
+    // Check ending with .js
+    if (!file.endsWith(".js")) {
+        console.error(`It should end with .js: ${file}`);
+        process.exit(1);
+    }
+
+    const parts = file.split("-");
+
+    // Should be at least 5 parts
+    if (parts.length < 5) {
+        console.error(`Invalid format: ${file}`);
+        process.exit(1);
+    }
+
+    // First part should be a year >= 2024
+    const year = parseInt(parts[0], 10);
+    if (isNaN(year) || year < 2023) {
+        console.error(`Invalid year: ${file}`);
+        process.exit(1);
+    }
+
+    // Second part should be a month
+    const month = parseInt(parts[1], 10);
+    if (isNaN(month) || month < 1 || month > 12) {
+        console.error(`Invalid month: ${file}`);
+        process.exit(1);
+    }
+
+    // Third part should be a day
+    const day = parseInt(parts[2], 10);
+    if (isNaN(day) || day < 1 || day > 31) {
+        console.error(`Invalid day: ${file}`);
+        process.exit(1);
+    }
+
+    // Fourth part should be HHmm
+    const time = parts[3];
+
+    // Check length is 4
+    if (time.length !== 4) {
+        console.error(`Invalid time: ${file}`);
+        process.exit(1);
+    }
+
+    const hour = parseInt(time.substring(0, 2), 10);
+    const minute = parseInt(time.substring(2), 10);
+    if (isNaN(hour) || hour < 0 || hour > 23 || isNaN(minute) || minute < 0 || minute > 59) {
+        console.error(`Invalid time: ${file}`);
+        process.exit(1);
+    }
+}
diff --git a/package-lock.json b/package-lock.json
index a3c5dc237..100cdcd88 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -46,7 +46,7 @@
                 "jsonwebtoken": "~9.0.0",
                 "jwt-decode": "~3.1.2",
                 "kafkajs": "^2.2.4",
-                "knex": "^2.4.2",
+                "knex": "~3.1.0",
                 "limiter": "~2.1.0",
                 "liquidjs": "^10.7.0",
                 "marked": "^14.0.0",
@@ -54,7 +54,7 @@
                 "mongodb": "~4.17.1",
                 "mqtt": "~4.3.7",
                 "mssql": "~11.0.0",
-                "mysql2": "~3.9.6",
+                "mysql2": "~3.11.3",
                 "nanoid": "~3.3.4",
                 "net-snmp": "^3.11.2",
                 "node-cloudflared-tunnel": "~1.0.9",
@@ -5655,6 +5655,15 @@
             "integrity": "sha512-aDczADvlvTGajTDjcjpJMqRkOF6Qdz3YbPZm/PyW6tKPkx2hlYBzxMhEywM/tU72HrVZjgl5VCdRuMlA7pZ8Gw==",
             "license": "MIT"
         },
+        "node_modules/aws-ssl-profiles": {
+            "version": "1.1.2",
+            "resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz",
+            "integrity": "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==",
+            "license": "MIT",
+            "engines": {
+                "node": ">= 6.0.0"
+            }
+        },
         "node_modules/axios": {
             "version": "0.28.1",
             "resolved": "https://registry.npmjs.org/axios/-/axios-0.28.1.tgz",
@@ -10915,9 +10924,9 @@
             }
         },
         "node_modules/knex": {
-            "version": "2.5.1",
-            "resolved": "https://registry.npmjs.org/knex/-/knex-2.5.1.tgz",
-            "integrity": "sha512-z78DgGKUr4SE/6cm7ku+jHvFT0X97aERh/f0MUKAKgFnwCYBEW4TFBqtHWFYiJFid7fMrtpZ/gxJthvz5mEByA==",
+            "version": "3.1.0",
+            "resolved": "https://registry.npmjs.org/knex/-/knex-3.1.0.tgz",
+            "integrity": "sha512-GLoII6hR0c4ti243gMs5/1Rb3B+AjwMOfjYm97pu0FOQa7JH56hgBxYf5WK2525ceSbBY1cjeZ9yk99GPMB6Kw==",
             "license": "MIT",
             "dependencies": {
                 "colorette": "2.0.19",
@@ -10929,7 +10938,7 @@
                 "getopts": "2.3.0",
                 "interpret": "^2.2.0",
                 "lodash": "^4.17.21",
-                "pg-connection-string": "2.6.1",
+                "pg-connection-string": "2.6.2",
                 "rechoir": "^0.8.0",
                 "resolve-from": "^5.0.0",
                 "tarn": "^3.0.2",
@@ -10939,7 +10948,7 @@
                 "knex": "bin/cli.js"
             },
             "engines": {
-                "node": ">=12"
+                "node": ">=16"
             },
             "peerDependenciesMeta": {
                 "better-sqlite3": {
@@ -10989,9 +10998,9 @@
             "license": "MIT"
         },
         "node_modules/knex/node_modules/pg-connection-string": {
-            "version": "2.6.1",
-            "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.1.tgz",
-            "integrity": "sha512-w6ZzNu6oMmIzEAYVw+RLK0+nqHPt8K3ZnknKi+g48Ak2pr3dtljJW3o+D/n2zzCG07Zoe9VOX3aiKpj+BN0pjg==",
+            "version": "2.6.2",
+            "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.2.tgz",
+            "integrity": "sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==",
             "license": "MIT"
         },
         "node_modules/knex/node_modules/resolve-from": {
@@ -11242,6 +11251,21 @@
                 "node": ">=10"
             }
         },
+        "node_modules/lru.min": {
+            "version": "1.1.1",
+            "resolved": "https://registry.npmjs.org/lru.min/-/lru.min-1.1.1.tgz",
+            "integrity": "sha512-FbAj6lXil6t8z4z3j0E5mfRlPzxkySotzUHwRXjlpRh10vc6AI6WN62ehZj82VG7M20rqogJ0GLwar2Xa05a8Q==",
+            "license": "MIT",
+            "engines": {
+                "bun": ">=1.0.0",
+                "deno": ">=1.30.0",
+                "node": ">=8.0.0"
+            },
+            "funding": {
+                "type": "github",
+                "url": "https://github.com/sponsors/wellwelwel"
+            }
+        },
         "node_modules/magic-string": {
             "version": "0.30.12",
             "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.12.tgz",
@@ -11917,16 +11941,17 @@
             }
         },
         "node_modules/mysql2": {
-            "version": "3.9.9",
-            "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.9.9.tgz",
-            "integrity": "sha512-Qtb2RUxwWMFkWXqF7Rd/7ySkupbQnNY7O0zQuQYgPcuJZ06M36JG3HIDEh/pEeq7LImcvA6O3lOVQ9XQK+HEZg==",
+            "version": "3.11.3",
+            "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.11.3.tgz",
+            "integrity": "sha512-Qpu2ADfbKzyLdwC/5d4W7+5Yz7yBzCU05YWt5npWzACST37wJsB23wgOSo00qi043urkiRwXtEvJc9UnuLX/MQ==",
             "license": "MIT",
             "dependencies": {
+                "aws-ssl-profiles": "^1.1.1",
                 "denque": "^2.1.0",
                 "generate-function": "^2.3.1",
                 "iconv-lite": "^0.6.3",
                 "long": "^5.2.1",
-                "lru-cache": "^8.0.0",
+                "lru.min": "^1.0.0",
                 "named-placeholders": "^1.1.3",
                 "seq-queue": "^0.0.5",
                 "sqlstring": "^2.3.2"
@@ -11935,15 +11960,6 @@
                 "node": ">= 8.0"
             }
         },
-        "node_modules/mysql2/node_modules/lru-cache": {
-            "version": "8.0.5",
-            "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-8.0.5.tgz",
-            "integrity": "sha512-MhWWlVnuab1RG5/zMRRcVGXZLCXrZTgfwMikgzCegsPnG62yDQo5JnqKkrK4jO5iKqDAZGItAqN5CtKBCBWRUA==",
-            "license": "ISC",
-            "engines": {
-                "node": ">=16.14"
-            }
-        },
         "node_modules/named-placeholders": {
             "version": "1.1.3",
             "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.3.tgz",
diff --git a/package.json b/package.json
index a0fabbe4a..ad9aac913 100644
--- a/package.json
+++ b/package.json
@@ -109,7 +109,7 @@
         "jsonwebtoken": "~9.0.0",
         "jwt-decode": "~3.1.2",
         "kafkajs": "^2.2.4",
-        "knex": "^2.4.2",
+        "knex": "~3.1.0",
         "limiter": "~2.1.0",
         "liquidjs": "^10.7.0",
         "marked": "^14.0.0",
@@ -117,7 +117,7 @@
         "mongodb": "~4.17.1",
         "mqtt": "~4.3.7",
         "mssql": "~11.0.0",
-        "mysql2": "~3.9.6",
+        "mysql2": "~3.11.3",
         "nanoid": "~3.3.4",
         "net-snmp": "^3.11.2",
         "node-cloudflared-tunnel": "~1.0.9",