diff --git a/src/python/grpcio/grpc/_adapter/_c/module.c b/src/python/grpcio/grpc/_adapter/_c/module.c
index 1f3aedd9d85f4977cc522c48894ac9832ef701ae..9b93b051f67e4f025654f7cb4405f1c8744900dd 100644
--- a/src/python/grpcio/grpc/_adapter/_c/module.c
+++ b/src/python/grpcio/grpc/_adapter/_c/module.c
@@ -53,6 +53,12 @@ PyMODINIT_FUNC init_c(void) {
     return;
   }
 
+  if (PyModule_AddStringConstant(
+          module, "PRIMARY_USER_AGENT_KEY",
+          GRPC_ARG_PRIMARY_USER_AGENT_STRING) < 0) {
+    return;
+  }
+
   /* GRPC maintains an internal counter of how many times it has been
      initialized and handles multiple pairs of grpc_init()/grpc_shutdown()
      invocations accordingly. */
diff --git a/src/python/grpcio/grpc/_adapter/_low.py b/src/python/grpcio/grpc/_adapter/_low.py
index dcf67dbc11732f5abc9dd7ea31b14ccc042b6ed2..239aac81b2ab0f2c235a6e7e00cafb7bac5243f6 100644
--- a/src/python/grpcio/grpc/_adapter/_low.py
+++ b/src/python/grpcio/grpc/_adapter/_low.py
@@ -27,9 +27,12 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+from grpc import _grpcio_metadata
 from grpc._adapter import _c
 from grpc._adapter import _types
 
+_USER_AGENT = 'Python-gRPC-{}'.format(_grpcio_metadata.__version__)
+
 ClientCredentials = _c.ClientCredentials
 ServerCredentials = _c.ServerCredentials
 
@@ -76,6 +79,7 @@ class Call(_types.Call):
 class Channel(_types.Channel):
 
   def __init__(self, target, args, creds=None):
+    args = list(args) + [(_c.PRIMARY_USER_AGENT_KEY, _USER_AGENT)]
     if creds is None:
       self.channel = _c.Channel(target, args)
     else:
diff --git a/src/python/grpcio_test/grpc_test/_adapter/_low_test.py b/src/python/grpcio_test/grpc_test/_adapter/_low_test.py
index 9a8edfad0cbb4fd2650aed9a5b50bff0abf31804..b6583662f345a4b462aeda5d192281b11f2d897b 100644
--- a/src/python/grpcio_test/grpc_test/_adapter/_low_test.py
+++ b/src/python/grpcio_test/grpc_test/_adapter/_low_test.py
@@ -31,11 +31,12 @@ import threading
 import time
 import unittest
 
+from grpc import _grpcio_metadata
 from grpc._adapter import _types
 from grpc._adapter import _low
 
 
-def WaitForEvents(completion_queues, deadline):
+def wait_for_events(completion_queues, deadline):
   """
   Args:
     completion_queues: list of completion queues to wait for events on
@@ -62,6 +63,7 @@ def WaitForEvents(completion_queues, deadline):
     thread.join()
   return results
 
+
 class InsecureServerInsecureClient(unittest.TestCase):
 
   def setUp(self):
@@ -123,16 +125,21 @@ class InsecureServerInsecureClient(unittest.TestCase):
     ], client_call_tag)
     self.assertEquals(_types.CallError.OK, client_start_batch_result)
 
-    client_no_event, request_event, = WaitForEvents([self.client_completion_queue, self.server_completion_queue], time.time() + 2)
+    client_no_event, request_event, = wait_for_events([self.client_completion_queue, self.server_completion_queue], time.time() + 2)
     self.assertEquals(client_no_event, None)
     self.assertEquals(_types.EventType.OP_COMPLETE, request_event.type)
     self.assertIsInstance(request_event.call, _low.Call)
     self.assertIs(server_request_tag, request_event.tag)
     self.assertEquals(1, len(request_event.results))
-    got_initial_metadata = dict(request_event.results[0].initial_metadata)
+    received_initial_metadata = dict(request_event.results[0].initial_metadata)
+    # Check that our metadata were transmitted
     self.assertEquals(
         dict(client_initial_metadata),
-        dict((x, got_initial_metadata[x]) for x in zip(*client_initial_metadata)[0]))
+        dict((x, received_initial_metadata[x]) for x in zip(*client_initial_metadata)[0]))
+    # Check that Python's user agent string is a part of the full user agent
+    # string
+    self.assertIn('Python-gRPC-{}'.format(_grpcio_metadata.__version__),
+                  received_initial_metadata['user-agent'])
     self.assertEquals(METHOD, request_event.call_details.method)
     self.assertEquals(HOST, request_event.call_details.host)
     self.assertLess(abs(DEADLINE - request_event.call_details.deadline), DEADLINE_TOLERANCE)
@@ -150,7 +157,7 @@ class InsecureServerInsecureClient(unittest.TestCase):
     ], server_call_tag)
     self.assertEquals(_types.CallError.OK, server_start_batch_result)
 
-    client_event, server_event, = WaitForEvents([self.client_completion_queue, self.server_completion_queue], time.time() + 1)
+    client_event, server_event, = wait_for_events([self.client_completion_queue, self.server_completion_queue], time.time() + 1)
 
     self.assertEquals(6, len(client_event.results))
     found_client_op_types = set()