diff --git a/src/core/surface/call.c b/src/core/surface/call.c
index 74df5745b5d05653c70143c744699d5127402dce..5e47f71f4114477fc89caf15ce7b7512d08d2718 100644
--- a/src/core/surface/call.c
+++ b/src/core/surface/call.c
@@ -820,7 +820,6 @@ static int fill_send_ops(grpc_call *call, grpc_transport_op *op) {
   grpc_ioreq_data data;
   grpc_metadata_batch mdb;
   size_t i;
-  char status_str[GPR_LTOA_MIN_BUFSIZE];
   GPR_ASSERT(op->send_ops == NULL);
 
   switch (call->write_state) {
@@ -865,13 +864,10 @@ static int fill_send_ops(grpc_call *call, grpc_transport_op *op) {
           /* send status */
           /* TODO(ctiller): cache common status values */
           data = call->request_data[GRPC_IOREQ_SEND_STATUS];
-          gpr_ltoa(data.send_status.code, status_str);
           grpc_metadata_batch_add_tail(
               &mdb, &call->status_link,
-              grpc_mdelem_from_metadata_strings(
-                  call->metadata_context,
-                  grpc_mdstr_ref(grpc_channel_get_status_string(call->channel)),
-                  grpc_mdstr_from_string(call->metadata_context, status_str)));
+              grpc_channel_get_reffed_status_elem(call->channel,
+                                                  data.send_status.code));
           if (data.send_status.details) {
             grpc_metadata_batch_add_tail(
                 &mdb, &call->details_link,
diff --git a/src/core/surface/channel.c b/src/core/surface/channel.c
index 947011c613f61058cce22af56501c913cb1f724b..e2c7f626656558dc16f636351e8ed4f6964d1b28 100644
--- a/src/core/surface/channel.c
+++ b/src/core/surface/channel.c
@@ -37,12 +37,15 @@
 #include <string.h>
 
 #include "src/core/iomgr/iomgr.h"
+#include "src/core/support/string.h"
 #include "src/core/surface/call.h"
 #include "src/core/surface/client.h"
 #include "src/core/surface/init.h"
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 
+#define NUM_CACHED_STATUS_ELEMS 3
+
 typedef struct registered_call {
   grpc_mdelem *path;
   grpc_mdelem *authority;
@@ -58,6 +61,7 @@ struct grpc_channel {
   grpc_mdstr *grpc_message_string;
   grpc_mdstr *path_string;
   grpc_mdstr *authority_string;
+  grpc_mdelem *grpc_status_elem[NUM_CACHED_STATUS_ELEMS];
 
   gpr_mu registered_call_mu;
   registered_call *registered_calls;
@@ -88,6 +92,13 @@ grpc_channel *grpc_channel_create_from_filters(
   channel->metadata_context = mdctx;
   channel->grpc_status_string = grpc_mdstr_from_string(mdctx, "grpc-status");
   channel->grpc_message_string = grpc_mdstr_from_string(mdctx, "grpc-message");
+  for (i = 0; i < NUM_CACHED_STATUS_ELEMS; i++) {
+    char buf[GPR_LTOA_MIN_BUFSIZE];
+    gpr_ltoa(i, buf);
+    channel->grpc_status_elem[i] = grpc_mdelem_from_metadata_strings(
+        mdctx, grpc_mdstr_ref(channel->grpc_status_string),
+        grpc_mdstr_from_string(mdctx, buf));
+  }
   channel->path_string = grpc_mdstr_from_string(mdctx, ":path");
   channel->authority_string = grpc_mdstr_from_string(mdctx, ":authority");
   grpc_channel_stack_init(filters, num_filters, args, channel->metadata_context,
@@ -175,6 +186,7 @@ void grpc_channel_internal_ref(grpc_channel *channel) {
 
 static void destroy_channel(void *p, int ok) {
   grpc_channel *channel = p;
+  size_t i;
   grpc_channel_stack_destroy(CHANNEL_STACK_FROM_CHANNEL(channel));
   grpc_mdstr_unref(channel->grpc_status_string);
   grpc_mdstr_unref(channel->grpc_message_string);
@@ -187,6 +199,9 @@ static void destroy_channel(void *p, int ok) {
     grpc_mdelem_unref(rc->authority);
     gpr_free(rc);
   }
+  for (i = 0; i < NUM_CACHED_STATUS_ELEMS; i++) {
+    grpc_mdelem_unref(channel->grpc_status_elem[i]);
+  }
   grpc_mdctx_unref(channel->metadata_context);
   gpr_mu_destroy(&channel->registered_call_mu);
   gpr_free(channel);
@@ -235,6 +250,18 @@ grpc_mdstr *grpc_channel_get_status_string(grpc_channel *channel) {
   return channel->grpc_status_string;
 }
 
+grpc_mdelem *grpc_channel_get_reffed_status_elem(grpc_channel *channel, int i) {
+  if (i >= 0 && i < NUM_CACHED_STATUS_ELEMS) {
+    return grpc_mdelem_ref(channel->grpc_status_elem[i]);
+  } else {
+    char tmp[GPR_LTOA_MIN_BUFSIZE];
+    gpr_ltoa(i, tmp);
+    return grpc_mdelem_from_metadata_strings(
+        channel->metadata_context, channel->grpc_status_string,
+        grpc_mdstr_from_string(channel->metadata_context, tmp));
+  }
+}
+
 grpc_mdstr *grpc_channel_get_message_string(grpc_channel *channel) {
   return channel->grpc_message_string;
 }
diff --git a/src/core/surface/channel.h b/src/core/surface/channel.h
index 388be357113378423f2aa395130ea3f55c929c08..fb57313041d574121de20b6e6532ec5841b73629 100644
--- a/src/core/surface/channel.h
+++ b/src/core/surface/channel.h
@@ -42,6 +42,8 @@ grpc_channel *grpc_channel_create_from_filters(
 
 grpc_channel_stack *grpc_channel_get_channel_stack(grpc_channel *channel);
 grpc_mdctx *grpc_channel_get_metadata_context(grpc_channel *channel);
+grpc_mdelem *grpc_channel_get_reffed_status_elem(grpc_channel *channel,
+                                                 int status_code);
 grpc_mdstr *grpc_channel_get_status_string(grpc_channel *channel);
 grpc_mdstr *grpc_channel_get_message_string(grpc_channel *channel);
 gpr_uint32 grpc_channel_get_max_message_length(grpc_channel *channel);