diff --git a/db/knex_migrations/2024-01-22-0000-stats-extras.js b/db/knex_migrations/2024-01-22-0000-stats-extras.js
new file mode 100644
index 000000000..b92e8892a
--- /dev/null
+++ b/db/knex_migrations/2024-01-22-0000-stats-extras.js
@@ -0,0 +1,26 @@
+exports.up = function (knex) {
+    return knex.schema
+        .alterTable("stat_daily", function (table) {
+            table.text("extras").defaultTo(null).comment("Extra statistics during this time period");
+        })
+        .alterTable("stat_minutely", function (table) {
+            table.text("extras").defaultTo(null).comment("Extra statistics during this time period");
+        })
+        .alterTable("stat_hourly", function (table) {
+            table.text("extras").defaultTo(null).comment("Extra statistics during this time period");
+        });
+
+};
+
+exports.down = function (knex) {
+    return knex.schema
+        .alterTable("stat_daily", function (table) {
+            table.dropColumn("extras");
+        })
+        .alterTable("stat_minutely", function (table) {
+            table.dropColumn("extras");
+        })
+        .alterTable("stat_hourly", function (table) {
+            table.dropColumn("extras");
+        });
+};
diff --git a/server/uptime-calculator.js b/server/uptime-calculator.js
index 9632e6eac..7b5326748 100644
--- a/server/uptime-calculator.js
+++ b/server/uptime-calculator.js
@@ -116,14 +116,23 @@ class UptimeCalculator {
         ]);
 
         for (let bean of minutelyStatBeans) {
-            let key = bean.timestamp;
-            this.minutelyUptimeDataList.push(key, {
+            let data = {
                 up: bean.up,
                 down: bean.down,
                 avgPing: bean.ping,
                 minPing: bean.pingMin,
                 maxPing: bean.pingMax,
-            });
+            };
+
+            if (bean.extras != null) {
+                data = {
+                    ...data,
+                    ...JSON.parse(bean.extras),
+                };
+            }
+
+            let key = bean.timestamp;
+            this.minutelyUptimeDataList.push(key, data);
         }
 
         // Load hourly data from database (recent 30 days only)
@@ -133,14 +142,22 @@ class UptimeCalculator {
         ]);
 
         for (let bean of hourlyStatBeans) {
-            let key = bean.timestamp;
-            this.hourlyUptimeDataList.push(key, {
+            let data = {
                 up: bean.up,
                 down: bean.down,
                 avgPing: bean.ping,
                 minPing: bean.pingMin,
                 maxPing: bean.pingMax,
-            });
+            };
+
+            if (bean.extras != null) {
+                data = {
+                    ...data,
+                    ...JSON.parse(bean.extras),
+                };
+            }
+
+            this.hourlyUptimeDataList.push(bean.timestamp, data);
         }
 
         // Load daily data from database (recent 365 days only)
@@ -150,14 +167,22 @@ class UptimeCalculator {
         ]);
 
         for (let bean of dailyStatBeans) {
-            let key = bean.timestamp;
-            this.dailyUptimeDataList.push(key, {
+            let data = {
                 up: bean.up,
                 down: bean.down,
                 avgPing: bean.ping,
                 minPing: bean.pingMin,
                 maxPing: bean.pingMax,
-            });
+            };
+
+            if (bean.extras != null) {
+                data = {
+                    ...data,
+                    ...JSON.parse(bean.extras),
+                };
+            }
+
+            this.dailyUptimeDataList.push(bean.timestamp, data);
         }
     }
 
@@ -170,11 +195,6 @@ class UptimeCalculator {
     async update(status, ping = 0) {
         let date = this.getCurrentDate();
 
-        // Don't count MAINTENANCE into uptime
-        if (status === MAINTENANCE) {
-            return date;
-        }
-
         let flatStatus = this.flatStatus(status);
 
         if (flatStatus === DOWN && ping > 0) {
@@ -189,7 +209,12 @@ class UptimeCalculator {
         let hourlyData = this.hourlyUptimeDataList[hourlyKey];
         let dailyData = this.dailyUptimeDataList[dailyKey];
 
-        if (flatStatus === UP) {
+        if (status === MAINTENANCE) {
+            minutelyData.maintenance = minutelyData.maintenance ? minutelyData.maintenance + 1 : 1;
+            hourlyData.maintenance = hourlyData.maintenance ? hourlyData.maintenance + 1 : 1;
+            dailyData.maintenance = dailyData.maintenance ? dailyData.maintenance + 1 : 1;
+
+        } else if (flatStatus === UP) {
             minutelyData.up += 1;
             hourlyData.up += 1;
             dailyData.up += 1;
@@ -233,7 +258,7 @@ class UptimeCalculator {
                 }
             }
 
-        } else {
+        } else if (flatStatus === DOWN) {
             minutelyData.down += 1;
             hourlyData.down += 1;
             dailyData.down += 1;
@@ -263,6 +288,13 @@ class UptimeCalculator {
         dailyStatBean.ping = dailyData.avgPing;
         dailyStatBean.pingMin = dailyData.minPing;
         dailyStatBean.pingMax = dailyData.maxPing;
+        {
+            // eslint-disable-next-line no-unused-vars
+            const { up, down, avgPing, minPing, maxPing, ...extras } = dailyData;
+            if (Object.keys(extras).length > 0) {
+                dailyStatBean.extras = JSON.stringify(extras);
+            }
+        }
         await R.store(dailyStatBean);
 
         let hourlyStatBean = await this.getHourlyStatBean(hourlyKey);
@@ -271,6 +303,13 @@ class UptimeCalculator {
         hourlyStatBean.ping = hourlyData.avgPing;
         hourlyStatBean.pingMin = hourlyData.minPing;
         hourlyStatBean.pingMax = hourlyData.maxPing;
+        {
+            // eslint-disable-next-line no-unused-vars
+            const { up, down, avgPing, minPing, maxPing, ...extras } = hourlyData;
+            if (Object.keys(extras).length > 0) {
+                hourlyStatBean.extras = JSON.stringify(extras);
+            }
+        }
         await R.store(hourlyStatBean);
 
         let minutelyStatBean = await this.getMinutelyStatBean(divisionKey);
@@ -279,6 +318,13 @@ class UptimeCalculator {
         minutelyStatBean.ping = minutelyData.avgPing;
         minutelyStatBean.pingMin = minutelyData.minPing;
         minutelyStatBean.pingMax = minutelyData.maxPing;
+        {
+            // eslint-disable-next-line no-unused-vars
+            const { up, down, avgPing, minPing, maxPing, ...extras } = minutelyData;
+            if (Object.keys(extras).length > 0) {
+                minutelyStatBean.extras = JSON.stringify(extras);
+            }
+        }
         await R.store(minutelyStatBean);
 
         // Remove the old data
@@ -474,7 +520,7 @@ class UptimeCalculator {
     flatStatus(status) {
         switch (status) {
             case UP:
-            // case MAINTENANCE:
+            case MAINTENANCE:
                 return UP;
             case DOWN:
             case PENDING:
@@ -606,7 +652,11 @@ class UptimeCalculator {
             avgPing = totalPing / total.up;
         }
 
-        uptimeData.uptime = total.up / (total.up + total.down);
+        if (total.up + total.down === 0) {
+            uptimeData.uptime = 0;
+        } else {
+            uptimeData.uptime = total.up / (total.up + total.down);
+        }
         uptimeData.avgPing = avgPing;
         return uptimeData;
     }