diff --git a/include/ajax.search.php b/include/ajax.search.php
index dbc0a291b86d3c7bebb6f1c67333735b23739b9e..fabe2d810fdd8e694d566b418b656c028e94a916 100644
--- a/include/ajax.search.php
+++ b/include/ajax.search.php
@@ -395,7 +395,7 @@ class SearchAjaxAPI extends AjaxController {
         if ($ids && is_array($ids))
             $criteria = array('id__in' => $ids);
 
-        $counts = SavedQueue::ticketsCount($thisstaff, $criteria, 'q');
+        $counts = SavedQueue::counts($thisstaff, $criteria);
         Http::response(200, false, 'application/json');
         return $this->encode($counts);
     }
diff --git a/include/class.search.php b/include/class.search.php
index aa2919910bc918f5843b7c247e986bac6a5263a2..29dd562fc2c38633824950abd3921cf437ae95f0 100644
--- a/include/class.search.php
+++ b/include/class.search.php
@@ -848,18 +848,40 @@ class SavedQueue extends CustomQueue {
         return (!$errors);
     }
 
-    static function ticketsCount($agent, $criteria=array(),
-            $prefix='') {
+    function getCount($agent, $cached=true) {
+        $criteria = $cached ? array() : array('id' => $this->getId());
+        $counts = self::counts($agent, $criteria, $cached);
+        return $counts["q{$this->getId()}"] ?: 0;
+    }
+
+    // Get ticket counts for queues the agent has acces to.
+    static function counts($agent, $criteria=array(), $cached=true) {
 
         if (!$agent instanceof Staff)
             return array();
 
-        if (function_exists('apcu_store')) {
-            $key = "counts.queues.{$agent->getId()}.".SECRET_SALT;
-            $cached = false;
-            $counts = apcu_fetch($key, $cached);
-            if ($cached === true)
-                return $counts;
+        // Cache TLS in seconds
+        $ttl = 3600;
+        // Cache key based on agent and salt of the installation
+        $key = "counts.queues.{$agent->getId()}.".SECRET_SALT;
+        if ($criteria && is_array($criteria)) // Consider additional criteria.
+            $key .= '.'.md5(serialize($criteria));
+
+        // only consider cache if requesed
+        if ($cached) {
+            if (function_exists('apcu_store')) {
+                $found = false;
+                $counts = apcu_fetch($key, $found);
+                if ($found === true)
+                    return $counts;
+            } elseif (isset($_SESSION[$key])
+                    && isset($_SESSION[$key]['qcount'])
+                    && (time() - $_SESSION[$key]['time']) < $ttl) {
+                return $_SESSION[$key]['qcount'];
+            } else {
+                // Auto clear missed session cache (if any)
+                unset($_SESSION[$key]);
+            }
         }
 
         $queues = static::objects()
@@ -868,7 +890,7 @@ class SavedQueue extends CustomQueue {
                 'staff_id' => $agent->getId(),
             )));
 
-        if ($criteria)
+        if ($criteria && is_array($criteria))
             $queues->filter($criteria);
 
         $query = Ticket::objects();
@@ -879,15 +901,18 @@ class SavedQueue extends CustomQueue {
             $Q = $queue->getBasicQuery();
             $expr = SqlCase::N()->when(new SqlExpr(new Q($Q->constraints)), new SqlField('ticket_id'));
             $query->aggregate(array(
-                "$prefix{$queue->id}" => SqlAggregate::COUNT($expr, true)
+                "q{$queue->id}" => SqlAggregate::COUNT($expr, true)
             ));
         }
 
         $counts = $query->values()->one();
-
+        // Always cache the results
         if (function_exists('apcu_store')) {
-            $key = "counts.queues.{$agent->getId()}.".SECRET_SALT;
-            apcu_store($key, $counts, 3600);
+            apcu_store($key, $counts, $ttl);
+        } else {
+            // Poor man's cache
+            $_SESSION[$key]['qcount'] = $counts;
+            $_SESSION[$key]['time'] = time();
         }
 
         return $counts;
@@ -895,9 +920,11 @@ class SavedQueue extends CustomQueue {
 
     static function clearCounts() {
         if (function_exists('apcu_store')) {
-            $regex = '/^counts.queues.\d+.' . preg_quote(SECRET_SALT, '/') . '$/';
-            foreach (new APCUIterator($regex, APC_ITER_KEY) as $key) {
-                apcu_delete($key);
+            if (class_exists('APCUIterator')) {
+                $regex = '/^counts.queues.\d+.' . preg_quote(SECRET_SALT, '/') . '$/';
+                foreach (new APCUIterator($regex, APC_ITER_KEY) as $key) {
+                    apcu_delete($key);
+                }
             }
             // Also clear rough counts
             apcu_delete("rough.counts.".SECRET_SALT);
diff --git a/include/staff/templates/queue-tickets.tmpl.php b/include/staff/templates/queue-tickets.tmpl.php
index 205ac43c339a21b1b9b89927f629fec6f78e5bb0..10a4cffba2e9fecb826ecba0e7b18837f12f1fac 100644
--- a/include/staff/templates/queue-tickets.tmpl.php
+++ b/include/staff/templates/queue-tickets.tmpl.php
@@ -76,7 +76,7 @@ if (!$sorted && isset($sort['queuesort'])) {
 $page = ($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1;
 $pageNav = new Pagenate(PHP_INT_MAX, $page, PAGE_LIMIT);
 $tickets = $pageNav->paginateSimple($tickets);
-$count = $queue->getRoughCount();
+$count = $queue->getCount($thisstaff);
 $pageNav->setTotal($count, true);
 $pageNav->setURL('tickets.php', $args);
 ?>
diff --git a/scp/autocron.php b/scp/autocron.php
index 170ab3a8b421286bdfe1db6a648a13e7b971946d..5f5da4fb29747af6e32e9c10533de6ea98c11527 100644
--- a/scp/autocron.php
+++ b/scp/autocron.php
@@ -45,6 +45,11 @@ if ($sec < 180 || !$ost || $ost->isUpgradePending())
 
 require_once(INCLUDE_DIR.'class.cron.php');
 
+// Run tickets count every 3rd run or so... force new count by skipping cached
+// results
+if (mt_rand(1, 12) == 3)
+    SavedQueue::counts($thisstaff, array(), false);
+
 // Clear staff obj to avoid false credit internal notes & auto-assignment
 $thisstaff = null;