diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py
--- a/django/db/models/fields/related.py
+++ b/django/db/models/fields/related.py
@@ -353,8 +353,9 @@
     """Creates a manager that subclasses 'superclass' (which is a Manager)
     and adds behavior for many-to-many related objects."""
     class ManyRelatedManager(superclass):
-        def __init__(self, model=None, core_filters=None, instance=None, symmetrical=None,
-                join_table=None, source_col_name=None, target_col_name=None):
+        def __init__(self, model=None, core_filters=None, instance=None,
+                     symmetrical=None, join_table=None, source_col_name=None,
+                     target_col_name=None, field_name=None):
             super(ManyRelatedManager, self).__init__()
             self.core_filters = core_filters
             self.model = model
@@ -365,6 +366,7 @@
             self.target_col_name = target_col_name
             self.through = through
             self._pk_val = self.instance._get_pk_val()
+            self.field_name = field_name
             if self._pk_val is None:
                 raise ValueError("%r instance needs to have a primary key value before a many-to-many relationship can be used." % instance.__class__.__name__)
 
@@ -434,10 +436,16 @@
                 existing_ids = set([row[0] for row in cursor.fetchall()])
 
                 # Add the ones that aren't there already
-                for obj_id in (new_ids - existing_ids):
+                new_ids = new_ids - existing_ids
+                for obj_id in new_ids:
                     cursor.execute("INSERT INTO %s (%s, %s) VALUES (%%s, %%s)" % \
                         (self.join_table, source_col_name, target_col_name),
                         [self._pk_val, obj_id])
+
+                added_objs = [obj for obj in objs if (isinstance(obj, self.model) and obj._get_pk_val() in new_ids) or obj in new_ids]
+                signals.m2m_add_items.send(sender=self.model, instance=self.instance,
+                                      field_name=self.field_name, objs=added_objs)
+
                 transaction.commit_unless_managed()
 
         def _remove_items(self, source_col_name, target_col_name, *objs):
@@ -460,10 +468,14 @@
                     (self.join_table, source_col_name,
                     target_col_name, ",".join(['%s'] * len(old_ids))),
                     [self._pk_val] + list(old_ids))
+                signals.m2m_remove_items.send(sender=self.model, instance=self.instance,
+                                              field_name=self.field_name, objs=objs)
                 transaction.commit_unless_managed()
 
         def _clear_items(self, source_col_name):
             # source_col_name: the PK colname in join_table for the source object
+            signals.m2m_clear_items.send(sender=self.model, instance=self.instance,
+                                         field_name=self.field_name)
             cursor = connection.cursor()
             cursor.execute("DELETE FROM %s WHERE %s = %%s" % \
                 (self.join_table, source_col_name),
@@ -500,7 +512,8 @@
             symmetrical=False,
             join_table=qn(self.related.field.m2m_db_table()),
             source_col_name=qn(self.related.field.m2m_reverse_name()),
-            target_col_name=qn(self.related.field.m2m_column_name())
+            target_col_name=qn(self.related.field.m2m_column_name()),
+            field_name=self.related.field.name
         )
 
         return manager
@@ -545,7 +558,8 @@
             symmetrical=(self.field.rel.symmetrical and instance.__class__ == rel_model),
             join_table=qn(self.field.m2m_db_table()),
             source_col_name=qn(self.field.m2m_column_name()),
-            target_col_name=qn(self.field.m2m_reverse_name())
+            target_col_name=qn(self.field.m2m_reverse_name()),
+            field_name=self.field.name
         )
 
         return manager
diff --git a/django/db/models/signals.py b/django/db/models/signals.py
--- a/django/db/models/signals.py
+++ b/django/db/models/signals.py
@@ -12,3 +12,7 @@
 post_delete = Signal(providing_args=["instance"])
 
 post_syncdb = Signal(providing_args=["class", "app", "created_models", "verbosity", "interactive"])
+
+m2m_add_items = Signal(providing_args=["instance", "field_name", "objs"])
+m2m_remove_items = Signal(providing_args=["instance", "field_name", "objs"])
+m2m_clear_items = Signal(providing_args=["instance", "field_name", "objs"])
