diff --git a/tools/patman/cser_helper.py b/tools/patman/cser_helper.py
index 31a5e3663dc..032d5218e9e 100644
--- a/tools/patman/cser_helper.py
+++ b/tools/patman/cser_helper.py
@@ -1378,6 +1378,29 @@ class CseriesHelper:
 
         return updated, 1 if cover else 0
 
+    def check_applied(self, svid, series_name, version):
+        """Check if all patches in a series version are accepted
+
+        If every patch has state 'accepted', notify the user that the
+        series has been applied upstream.
+
+        Args:
+            svid (int): Ser/ver ID
+            series_name (str): Series name (for display)
+            version (int): Version number (for display)
+
+        Returns:
+            bool: True if all patches are accepted
+        """
+        pclist = self.db.pcommit_get_list(svid)
+        if not pclist:
+            return False
+        if all(pc.state == 'accepted' for pc in pclist):
+            tout.notice(f"Series '{series_name}' v{version}: all patches "
+                        'accepted upstream')
+            return True
+        return False
+
     async def _gather(self, pwork, link, show_cover_comments):
         """Sync the series status from patchwork
 
diff --git a/tools/patman/cseries.py b/tools/patman/cseries.py
index 74e86eeeb37..5ffc2989dd5 100644
--- a/tools/patman/cseries.py
+++ b/tools/patman/cseries.py
@@ -1343,6 +1343,7 @@ class Cseries(cser_helper.CseriesHelper):
 
             if not dry_run:
                 self.commit()
+                self.check_applied(svid, ser.name, version)
             else:
                 self.rollback()
                 tout.info('Dry run completed')
@@ -1377,8 +1378,14 @@ class Cseries(cser_helper.CseriesHelper):
                 f"{tot_cover} cover letter{'s' if tot_cover != 1 else ''} "
                 f'updated, {missing} missing '
                 f"link{'s' if missing != 1 else ''} ({requests} requests)")
+            applied = []
             if not dry_run:
                 self.commit()
+                for svid, sync in to_fetch.items():
+                    if self.check_applied(svid, sync.series_name, sync.version):
+                        applied.append(sync.series_name)
+                if applied:
+                    tout.notice(f'{len(applied)} series applied upstream')
             else:
                 self.rollback()
                 tout.info('Dry run completed')
