diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c
index cf79bda..96ea5f6 100644
--- a/gst/rtsp-server/rtsp-client.c
+++ b/gst/rtsp-server/rtsp-client.c
@@ -131,8 +131,8 @@ static void gst_rtsp_client_set_property (GObject * object, guint propid,
 static void gst_rtsp_client_finalize (GObject * obj);
 
 static GstSDPMessage *create_sdp (GstRTSPClient * client, GstRTSPMedia * media);
-static void client_session_finalized (GstRTSPClient * client,
-    GstRTSPSession * session);
+static void client_session_expired (GstRTSPSession * session,
+    GstRTSPClient * client);
 static void unlink_session_transports (GstRTSPClient * client,
     GstRTSPSession * session, GstRTSPSessionMedia * sessmedia);
 static gboolean default_configure_client_media (GstRTSPClient * client,
@@ -295,24 +295,51 @@ client_unlink_session (GstRTSPClient * client, GstRTSPSession * session)
 }
 
 static void
+client_destroy_handler_data (gpointer data)
+{
+  g_slice_free (gulong, data);
+}
+
+static void
+client_disconnect_expired_handler (GstRTSPSession * session)
+{
+  gulong *handler;
+
+  handler = g_object_get_data (G_OBJECT (session), "gst-rtsp-expired-handler");
+  if (handler == NULL)
+    return;
+
+  g_signal_handler_disconnect (G_OBJECT (session), *handler);
+  g_object_set_data (G_OBJECT (session), "gst-rtsp-expired-handler", NULL);
+}
+
+static void
 client_watch_session (GstRTSPClient * client, GstRTSPSession * session)
 {
   GstRTSPClientPrivate *priv = client->priv;
-  GList *walk;
+  gulong *handler;
 
-  for (walk = priv->sessions; walk; walk = g_list_next (walk)) {
-    GstRTSPSession *msession = (GstRTSPSession *) walk->data;
+  g_mutex_lock (&priv->lock);
 
-    /* we already know about this session */
-    if (msession == session)
-      return;
+  /* we already know about this session */
+  if (g_list_index (priv->sessions, session) != -1) {
+    g_mutex_unlock (&priv->lock);
+    return;
   }
 
   GST_INFO ("watching session %p", session);
 
-  g_object_weak_ref (G_OBJECT (session), (GWeakNotify) client_session_finalized,
-      client);
-  priv->sessions = g_list_prepend (priv->sessions, session);
+  priv->sessions = g_list_prepend (priv->sessions, g_object_ref (session));
+  handler = g_slice_new (gulong);
+  /* this extra client ref will be dropped either in teardown or in session
+   * expire */
+  *handler = g_signal_connect_data (session, "expired",
+      (GCallback) client_session_expired, g_object_ref (client),
+      (GClosureNotify) g_object_unref, 0);
+  g_object_set_data_full (G_OBJECT (session), "gst-rtsp-expired-handler",
+      handler, client_destroy_handler_data);
+
+  g_mutex_unlock (&priv->lock);
 }
 
 static void
@@ -322,16 +349,21 @@ client_unwatch_session (GstRTSPClient * client, GstRTSPSession * session)
 
   GST_INFO ("unwatching session %p", session);
 
-  g_object_weak_unref (G_OBJECT (session),
-      (GWeakNotify) client_session_finalized, client);
-  priv->sessions = g_list_remove (priv->sessions, session);
+  client_disconnect_expired_handler (session);
+
+  g_mutex_lock (&priv->lock);
+  if (g_list_index (priv->sessions, session) != -1) {
+    priv->sessions = g_list_remove (priv->sessions, session);
+    g_object_unref (session);
+  }
+  g_mutex_unlock (&priv->lock);
 }
 
 static void
 client_cleanup_session (GstRTSPClient * client, GstRTSPSession * session)
 {
-  g_object_weak_unref (G_OBJECT (session),
-      (GWeakNotify) client_session_finalized, client);
+  client_disconnect_expired_handler (session);
+
   client_unlink_session (client, session);
 }
 
@@ -341,12 +373,13 @@ client_cleanup_sessions (GstRTSPClient * client)
   GstRTSPClientPrivate *priv = client->priv;
   GList *sessions;
 
-  /* remove weak-ref from sessions */
+  g_mutex_lock (&priv->lock);
   for (sessions = priv->sessions; sessions; sessions = g_list_next (sessions)) {
     client_cleanup_session (client, (GstRTSPSession *) sessions->data);
   }
-  g_list_free (priv->sessions);
+  g_list_free_full (priv->sessions, g_object_unref);
   priv->sessions = NULL;
+  g_mutex_unlock (&priv->lock);
 }
 
 /* A client is finalized when the connection is broken */
@@ -2213,7 +2246,7 @@ sanitize_uri (GstRTSPUrl * uri)
 }
 
 static void
-client_session_finalized (GstRTSPClient * client, GstRTSPSession * session)
+client_session_expired (GstRTSPSession * session, GstRTSPClient * client)
 {
   GstRTSPClientPrivate *priv = client->priv;
 
@@ -2222,12 +2255,23 @@ client_session_finalized (GstRTSPClient * client, GstRTSPSession * session)
   /* unlink all media managed in this session */
   client_unlink_session (client, session);
 
-  /* remove the session */
-  if (!(priv->sessions = g_list_remove (priv->sessions, session))) {
-    GST_INFO ("client %p: all sessions finalized, close the connection",
-        client);
-    close_connection (client);
+  g_mutex_lock (&priv->lock);
+
+  if (g_list_index (priv->sessions, session) != -1) {
+    /* remove the session */
+    if (!(priv->sessions = g_list_remove (priv->sessions, session))) {
+      GST_INFO ("client %p: all sessions finalized, close the connection",
+          client);
+      close_connection (client);
+    }
+    g_object_unref (session);
   }
+
+  g_mutex_unlock (&priv->lock);
+
+  /* session expired, handler no longer nedded, this will also drop
+   * handlers ref to the client */
+  client_disconnect_expired_handler (session);
 }
 
 /* Returns TRUE if there are no Require headers, otherwise returns FALSE
diff --git a/gst/rtsp-server/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c
index 5111eaa..947e522 100644
--- a/gst/rtsp-server/rtsp-session-pool.c
+++ b/gst/rtsp-server/rtsp-session-pool.c
@@ -439,7 +439,15 @@ gst_rtsp_session_pool_remove (GstRTSPSessionPool * pool, GstRTSPSession * sess)
 static gboolean
 cleanup_func (gchar * sessionid, GstRTSPSession * sess, GTimeVal * now)
 {
-  return gst_rtsp_session_is_expired (sess, now);
+  gboolean expired;
+
+  expired = gst_rtsp_session_is_expired (sess, now);
+  if (expired) {
+    GST_DEBUG ("session expired, emitting signal");
+    g_signal_emit_by_name (G_OBJECT (sess), "expired", NULL);
+  }
+
+  return expired;
 }
 
 /**
diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c
index 9beb8ab..20f89f4 100644
--- a/gst/rtsp-server/rtsp-session.c
+++ b/gst/rtsp-server/rtsp-session.c
@@ -78,9 +78,17 @@ enum
   PROP_LAST
 };
 
+enum
+{
+  SIGNAL_EXPIRED,
+  SIGNAL_LAST
+};
+
 GST_DEBUG_CATEGORY_STATIC (rtsp_session_debug);
 #define GST_CAT_DEFAULT rtsp_session_debug
 
+static guint gst_rtsp_session_signals[SIGNAL_LAST] = { 0 };
+
 static void gst_rtsp_session_get_property (GObject * object, guint propid,
     GValue * value, GParamSpec * pspec);
 static void gst_rtsp_session_set_property (GObject * object, guint propid,
@@ -117,6 +125,11 @@ gst_rtsp_session_class_init (GstRTSPSessionClass * klass)
           "timeout always visible in header",
           DEFAULT_ALWAYS_VISIBLE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
+  gst_rtsp_session_signals[SIGNAL_EXPIRED] =
+      g_signal_new ("expired", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
+      G_STRUCT_OFFSET (GstRTSPSessionClass, expired), NULL, NULL,
+      g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
+
   GST_DEBUG_CATEGORY_INIT (rtsp_session_debug, "rtspsession", 0,
       "GstRTSPSession");
 }
diff --git a/gst/rtsp-server/rtsp-session.h b/gst/rtsp-server/rtsp-session.h
index d9c0f18..8055161 100644
--- a/gst/rtsp-server/rtsp-session.h
+++ b/gst/rtsp-server/rtsp-session.h
@@ -72,9 +72,17 @@ struct _GstRTSPSession {
   gpointer _gst_reserved[GST_PADDING];
 };
 
+/**
+ * GstRTSPSessionClass:
+ *
+ * @expired: Reports that the session has expired
+ */
 struct _GstRTSPSessionClass {
   GObjectClass  parent_class;
 
+  /* signals */
+  void     (*expired)                  (GstRTSPSession *session);
+
   /*< private >*/
   gpointer _gst_reserved[GST_PADDING];
 };
