diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index efc30f62f9b064c61efff391b26234b1cc324586..5abbfc51cebf7e63c334047c98ad10a694fc6302 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -184,7 +184,7 @@ For the compatibility column, the possible values are the following:
 | `moveid {from} {to}`                      | `moveid {from} {to}`                  | ~     | `to` is always an absolute position               |
 | `playlist`                                | `playlist`                            | +     |                                                   |
 | `playlistfind {tag} {needle}`             | `playlistfind {uri}`                  | ~     | uses lektord URIs                                 |
-| `playlistid {songid}`                     | `playlistid {id}                      | ~     | the uri is only an id                             |
+| `playlistid {songid}`                     | `playlistid {id}`                     | ~     | the uri is only an id                             |
 | `playlistinfo [[songpos]/[start:end]]`    | `playlistinfo`                        | -     | is an alias to `playlist`                         |
 | `playlistsearch {taf} {needle}`           | `playlistsearch {uri}`                | ~     | uses lektord URIs                                 |
 | `plchanges {version} [start:end]`         |                                       |       | not implemented                                   |
diff --git a/inc/lektor/net.h b/inc/lektor/net.h
index f7607f955385e7ed9ff67f417065a2c1daa5c4da..faec5d29af128d86caa0b1e58710dc299a7d5afb 100644
--- a/inc/lektor/net.h
+++ b/inc/lektor/net.h
@@ -54,7 +54,9 @@ struct lkt_state {
     /* The database */
     volatile sqlite3 *db;
     const char *kara_prefix;
-    volatile uint8_t is_updating;
+    uint64_t update_total;
+    uint64_t update_current;
+    uint8_t is_updating;
 
     /* Internal event flags */
     mpd_idle_flag mpd_idle_events;
diff --git a/inc/lektor/queue.h b/inc/lektor/queue.h
index b7f5367a0c130cdd5e81aa684a6a17ec8cfdedbf..464e3f8aff98b523c676e6b8ff263085bdf57a87 100644
--- a/inc/lektor/queue.h
+++ b/inc/lektor/queue.h
@@ -37,17 +37,19 @@ enum {
 #define LKT_DB_UPDATING_FINISHED ((void *) (size_t) __LKT_DB_UPDATING_FINISHED)
 
 enum lkt_event_type {
-    lkt_event_null          = 0,         // NULL
-    lkt_event_play_pos      = (1 <<  1), // size_t
-    lkt_event_play_file     = (1 <<  2), // XXX: UNUSED
-    lkt_event_play_next     = (1 <<  3), // NULL
-    lkt_event_play_prev     = (1 <<  4), // NULL
-    lkt_event_play_toggle   = (1 <<  5), // size_t, `LKT_PLAY_.*`
-    lkt_event_prop_vol      = (1 <<  6), // size_t
-    lkt_event_prop_dur      = (1 <<  7), // size_t
-    lkt_event_prop_time     = (1 <<  8), // size_t
-    lkt_event_skip_current  = (1 <<  9), // NULL
-    lkt_event_db_updating   = (1 << 10), // size_t, `LKT_DB_UPDATING_*`
+    lkt_event_null              = 0,         // NULL
+    lkt_event_play_pos          = (1 <<  1), // size_t
+    lkt_event_play_file         = (1 <<  2), // XXX: UNUSED
+    lkt_event_play_next         = (1 <<  3), // NULL
+    lkt_event_play_prev         = (1 <<  4), // NULL
+    lkt_event_play_toggle       = (1 <<  5), // size_t, `LKT_PLAY_.*`
+    lkt_event_prop_vol          = (1 <<  6), // size_t
+    lkt_event_prop_dur          = (1 <<  7), // size_t
+    lkt_event_prop_time         = (1 <<  8), // size_t
+    lkt_event_skip_current      = (1 <<  9), // NULL
+    lkt_event_db_updating       = (1 << 10), // size_t, `LKT_DB_UPDATING_*`
+    lkt_event_db_update_total   = (1 << 11), // size_t, update udapte_total reset update_current
+    lkt_event_db_update_tick    = (1 << 12), // NULL, increment the `update_current`
 };
 
 #define lkt_event_play ( lkt_event_play_pos    | lkt_event_play_file    \
diff --git a/src/base/commands.c b/src/base/commands.c
index fea011fc41beba86e544ccf7be2d531a7aad54f5..a2c3b1d16ff02b1bcd700e34fdbd7bff21c8010e 100644
--- a/src/base/commands.c
+++ b/src/base/commands.c
@@ -155,13 +155,14 @@ command_stats(struct lkt_state *srv, size_t c, char UNUSED *args[LKT_MESSAGE_ARG
      *              the sdl2 module and any player module) */
     out->data_len = safe_snprintf(out->data, LKT_MESSAGE_MAX,
                                   "__is_updating: %d\n" /* Custom field here */
+                                  "___update_progress: %ld:%ld\n"
                                   "db_update: %ld\n"
                                   "uptime: %ld\n"
                                   "artists: %d\n"       /* Number of authors */
                                   "albums: %d\n"        /* Number of source names */
                                   "songs: %d\n",        /* Number of songs */
-                                  srv->is_updating, (uint64_t) ts_update,
-                                  (uint64_t) (time(NULL) - srv->start_date),
+                                  srv->is_updating, srv->update_current, srv->update_total,
+                                  (uint64_t) ts_update, (uint64_t) (time(NULL) - srv->start_date),
                                   artists, albums, songs);
     lkt_state_send(srv, c, out);
     return true;
diff --git a/src/net/listen.c b/src/net/listen.c
index f8d2b94ff320ed2dc97c47666640e53976df3d83..284ff2c84d9433a6c7c1da6121e7c733588adad7 100644
--- a/src/net/listen.c
+++ b/src/net/listen.c
@@ -866,10 +866,18 @@ redo:
         free(string);
     })
 
-    __CASE(play_file, {})
-    __CASE(db_updating, { srv->is_updating = (uint8_t) (size_t) evt.attr; })
+    __CASE(db_updating,     { srv->is_updating = (((uint8_t) (size_t) evt.attr) > 0); })
+    __CASE(db_update_tick,  {
+        if (srv->update_current != ((size_t) -1))
+            srv->update_current++;
+    })
+    __CASE(db_update_total, {
+        srv->update_total   = (size_t) evt.attr;
+        srv->update_current = 0;
+    })
 
-    /* The null event, just return */
+    /* The null event / ignored events, just return / continue */
+    __CASE(play_file, {})
     case lkt_event_null:
         return;