Index: bin/php/ezsessiongc.php
===================================================================
--- bin/php/ezsessiongc.php	(revision 24389)
+++ bin/php/ezsessiongc.php	(working copy)
@@ -51,6 +51,15 @@
 if ( !$isQuiet )
     $cli->notice( "Cleaning up expired sessions." );
 
+// Functions for session to make sure baskets are cleaned up
+function eZSessionBasketGarbageCollector( $db, $time )
+{
+    eZBasket::cleanupExpired( $time );
+}
+
+// Fill in hooks
+eZSession::addCallback( 'gc_pre', 'eZSessionBasketGarbageCollector');
+
 eZSession::garbageCollector();
 
 $script->shutdown();
Index: cronjobs/session_gc.php
===================================================================
--- cronjobs/session_gc.php	(revision 24389)
+++ cronjobs/session_gc.php	(working copy)
@@ -41,6 +41,15 @@
  */
 
 
+// Functions for session to make sure baskets are cleaned up
+function eZSessionBasketGarbageCollector( $db, $time )
+{
+    eZBasket::cleanupExpired( $time );
+}
+
+// Fill in hooks
+eZSession::addCallback( 'gc_pre', 'eZSessionBasketGarbageCollector');
+
 eZSession::garbageCollector();
 
 ?>
Index: design/admin/templates/setup/session.tpl
===================================================================
--- design/admin/templates/setup/session.tpl	(revision 24389)
+++ design/admin/templates/setup/session.tpl	(working copy)
@@ -8,16 +8,21 @@
 {if $sessions_removed}
     {if $gc_sessions_completed}
 		<div class="message-feedback">
-		<h2><span class="time">[{currentdate()|l10n( shortdatetime )}]</span> {"The sessions were successfully removed."|i18n( "design/admin/setup/session" )}</h2>
+		    <h2><span class="time">[{currentdate()|l10n( shortdatetime )}]</span> {"The sessions were successfully removed."|i18n( "design/admin/setup/session" )}</h2>
 		</div>
     {else}
-		<div class="message-feedback">
-		    <h2><span class="time">[{currentdate()|l10n( shortdatetime )}]</span> {"Some timed out sessions were successfully removed."|i18n( "design/admin/setup/session" )}</h2>
-		    <p>
-		        {"But to avoid execution timeout you'll need to perform the action several times to complete the operation."|i18n( "design/admin/setup/session" )}<br />
-		        {"Alternatively clear the timed out session data from command-line using:"|i18n( "design/admin/setup/session" )} <i>&gt;php bin/php/ezsessiongc.php</i>
-		    </p>
-		</div>
+      <div class="message-warning">
+            <h2><span class="time">[{currentdate()|l10n( shortdatetime )}]</span> {"Not all timed out sessions were successfully removed."|i18n( "design/admin/setup/session" )}</h2>
+            <p>
+                {"The operation were cut short in order to avoid execution timeout."|i18n( "design/admin/setup/session" )}<br />
+                {"Your alternatives are to:"|i18n( "design/admin/setup/session" )}
+            </p>
+            <ul>
+                <li>{"Repeat the operation several times to complete it."|i18n( "design/admin/setup/session" )}</li>
+                <li>{"Clear the timed out session data from command-line using: &gt;php bin/php/ezsessiongc.php"|i18n( "design/admin/setup/session" )}</li>
+                <li>{"Install the session cleanup cronjob 'session_gc.php' and run on nightly intervals (see cronjob.ini or doc for how)"|i18n( "design/admin/setup/session" )}</li>
+            </ul>
+      </div>
     {/if}
 {/if}
 
Index: design/standard/templates/setup/session.tpl
===================================================================
--- design/standard/templates/setup/session.tpl	(revision 24389)
+++ design/standard/templates/setup/session.tpl	(working copy)
@@ -40,16 +40,21 @@
 
 {if $sessions_removed}
     {if $gc_sessions_completed}
-	  <div class="feedback">
-	    {"The sessions were successfully removed."|i18n( "design/standard/setup/session" )}
-	  </div>
+        <div class="message-feedback">
+            <h2><span class="time">[{currentdate()|l10n( shortdatetime )}]</span> {"The sessions were successfully removed."|i18n( "design/standard/setup/session" )}</h2>
+        </div>
 	{else}
-      <div class="feedback">
-            <h2>{"Some timed out sessions were successfully removed."|i18n( "design/admin/setup/session" )}</h2>
+      <div class="message-warning">
+            <h2><span class="time">[{currentdate()|l10n( shortdatetime )}]</span> {"Not all timed out sessions were successfully removed."|i18n( "design/standard/setup/session" )}</h2>
             <p>
-                {"But to avoid execution timeout you'll need to perform the action several times to complete the operation."|i18n( "design/admin/setup/session" )}<br />
-                {"Alternatively clear the timed out session data from command-line using:"|i18n( "design/admin/setup/session" )} <i>&gt;php bin/php/ezsessiongc.php</i>
+                {"The operation were cut short in order to avoid execution timeout."|i18n( "design/standard/setup/session" )}<br />
+                {"Your alternatives are to:"|i18n( "design/standard/setup/session" )}
             </p>
+            <ul>
+                <li>{"Repeat the operation several times to complete it."|i18n( "design/standard/setup/session" )}</li>
+                <li>{"Clear the timed out session data from command-line using: &gt;php bin/php/ezsessiongc.php"|i18n( "design/standard/setup/session" )}</li>
+                <li>{"Install the session cleanup cronjob 'session_gc.php' and run on nightly intervals (see cronjob.ini or doc for how)"|i18n( "design/standard/setup/session" )}</li>
+            </ul>
       </div>
     {/if}
 {/if}
Index: lib/ezutils/classes/ezsession.php
===================================================================
--- lib/ezutils/classes/ezsession.php	(revision 24389)
+++ lib/ezutils/classes/ezsession.php	(working copy)
@@ -85,6 +85,15 @@
     // Name of session handler, change if you override class with autoload
     const HANDLER_NAME = 'ezdb';
 
+    // Seconds before timeout occurs that gc function stops to make sure request completes 
+    const GC_TIMEOUT_MARGIN = 6;
+
+    // Max execution time if php's setting evaluates to false, to avoid hitting http server timeout
+    const GC_MAX_EXECUTION_TIME = 300;
+
+    // Same as above when in CLI mode
+    const GC_MAX_EXECUTION_TIME_CLI = 3000;
+
     /**
      * User id, see {@link eZSession::userID()}.
      *
@@ -330,40 +339,38 @@
      * Deletes all expired session data in the database, this function is 
      * register in {@link eZSession::registerFunctions()}
      * 
-     * @param int $commitrows When > 0, a db commit will be issue after every
-     *            chunk of commitrows has been deleted avoiding long table locks and and timeouts
-     *            if number is sufficiently low. 
+     * @param bool $noLockMode Will delete only small amounts of sessions at a time and stop before timing out
      * @return bool Return boolean to signal if gc completed or if it stopped to avoid timeout.
      */
-    static public function garbageCollector( $commitrows = 10000 )
+    static public function garbageCollector( $noLockMode = true )
     {
         $db = eZDB::instance();
         $gcCompleted = true;
         $requestTime = $_SERVER['REQUEST_TIME'];
-        // Get max execution time, set to 300 if unlimited to avoid triggering other timouts
-        $maxExecutionTime = ini_get( 'max_execution_time' ) || 300;
         self::triggerCallback( 'gc_pre', array( $db, $requestTime ) );
 
-        if ( $commitrows !== 0 )
+        if ( $noLockMode )
         {
-            // Calculate approx. the slicing of timestamps that will delete N rows at a time
-            // assuming that sessions are evenly distributed in time
-            $res = $db->arrayQuery( 'SELECT COUNT(*) AS count, MIN(expiration_time) AS oldest FROM ezsession WHERE expiration_time < ' . $requestTime );
-            if ( $res && $res[0]['count'] > 0 && $res[0]['oldest'] < $requestTime )
+            $maxExecutionTime = ini_get( 'max_execution_time' );
+            if ( !$maxExecutionTime )
             {
-                $date      = $res[0]['oldest'];
-                $timeslice = intval( $commitrows * ( $requestTime - $res[0]['oldest'] ) / $res[0]['count'] );
-                do
-                {
-                    $date += $timeslice;
-                    if ( $date > $requestTime ) $date = $requestTime;
-                    $db->query( 'DELETE FROM ezsession WHERE expiration_time < ' . $date );
-                    $db->commitquery();
-                    // Make sure we're in a safe distance (above 5 seconds) from execution timeout
-                    $withinTimout = ( time() - $requestTime  ) < ( $maxExecutionTime - 5 );
-                } while ( $date < $requestTime && $withinTimout );
-                $gcCompleted = $withinTimout || $date >= $requestTime;
+                if ( PHP_SAPI === 'cli' )
+                    $maxExecutionTime = self::GC_MAX_EXECUTION_TIME_CLI;
+                else
+                    $maxExecutionTime = self::GC_MAX_EXECUTION_TIME;
             }
+
+            do
+            {
+                $rows = $db->arrayQuery( 'SELECT session_key FROM ezsession WHERE expiration_time < ' . $requestTime,  array( 'offset' => 0, 'limit' => 20, 'column' => 'session_key' ) );
+                if ( $rows )
+                {
+                    $keyINString = '\'' . implode( '\', \'', $rows ) . '\'';
+                    $db->query( "DELETE FROM ezsession WHERE session_key IN ( $keyINString )" );
+                }
+                $withinTimout = ( time() - $requestTime  ) < ( $maxExecutionTime - self::GC_TIMEOUT_MARGIN );
+            } while ( $rows && $withinTimout );
+            $gcCompleted =  $withinTimout || !$rows;
         }
         else
         {
