diff --git a/client/client_priv.h b/client/client_priv.h
index e86a56f58c1093545d44006118890f038186902c..95f4d1051566dd1b0bff160a6e32dcbb95602364 100644
--- a/client/client_priv.h
+++ b/client/client_priv.h
@@ -49,4 +49,5 @@ enum options_client
 #ifdef HAVE_NDBCLUSTER_DB
   ,OPT_NDBCLUSTER,OPT_NDB_CONNECTSTRING
 #endif
+  ,OPT_IGNORE_TABLE
 };
diff --git a/client/mysqldump.c b/client/mysqldump.c
index be2abd1982246e0c0549e0fbb86456b2b21b504e..ffdb84397e93293c7f00c70c501ca02dfcd56129 100644
--- a/client/mysqldump.c
+++ b/client/mysqldump.c
@@ -43,6 +43,7 @@
 #include <my_sys.h>
 #include <m_string.h>
 #include <m_ctype.h>
+#include <hash.h>
 
 #include "client_priv.h"
 #include "mysql.h"
@@ -128,6 +129,16 @@ const char *compatible_mode_names[]=
 TYPELIB compatible_mode_typelib= {array_elements(compatible_mode_names) - 1,
 				  "", compatible_mode_names, NULL};
 
+#define TABLE_RULE_HASH_SIZE   16
+
+typedef struct st_table_rule_ent
+{
+  char* key;    /* dbname.tablename */
+  uint key_len;
+} TABLE_RULE_ENT;
+
+my_bool ignore_table_inited;
+HASH ignore_table;
 
 static struct my_option my_long_options[] =
 {
@@ -233,6 +244,11 @@ static struct my_option my_long_options[] =
    (gptr*) &opt_hex_blob, (gptr*) &opt_hex_blob, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
   {"host", 'h', "Connect to host.", (gptr*) &current_host,
    (gptr*) &current_host, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+  {"ignore-table", OPT_IGNORE_TABLE,
+   "Do not dump the specified table. To specify more than one table to ignore, "
+   "use the directive multiple times, once for each table.  Each table must "
+   "be specified with both database and table names, e.g. --ignore-table=database.table",
+   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
   {"lines-terminated-by", OPT_LTB, "Lines in the i.file are terminated by ...",
    (gptr*) &lines_terminated, (gptr*) &lines_terminated, 0, GET_STR,
    REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
@@ -502,6 +518,32 @@ static void write_footer(FILE *sql_file)
 } /* write_footer */
 
 
+static void free_table_ent(TABLE_RULE_ENT* e)
+{
+  my_free((gptr) e, MYF(0));
+}
+
+
+static byte* get_table_key(TABLE_RULE_ENT* e, uint* len,
+			   my_bool not_used __attribute__((unused)))
+{
+  *len= e->key_len;
+  return (byte*)e->key;
+}
+
+
+void init_table_rule_hash(HASH* h, bool* h_inited)
+{
+  if(hash_init(h, charset_info, TABLE_RULE_HASH_SIZE, 0, 0,
+	       (hash_get_key) get_table_key,
+	       (hash_free_key) free_table_ent, 0))
+  {
+    fprintf(stderr, "Internal hash initialization error\n");
+    exit(1);
+  }
+  *h_inited= 1;
+}
+
 
 static my_bool
 get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
@@ -573,6 +615,37 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
   case (int) OPT_TABLES:
     opt_databases=0;
     break;
+  case (int) OPT_IGNORE_TABLE:
+  {
+    const char* dot = strchr(argument, '.');
+    if (!dot) 
+    {
+      fprintf(stderr, "Illegal use of option --ignore-table=<database>.<table>\n");
+      exit(1);
+    }
+    // len is always > 0 because we know the there exists a '.'
+    uint len= (uint)strlen(argument);
+    TABLE_RULE_ENT* e= (TABLE_RULE_ENT*)my_malloc(sizeof(TABLE_RULE_ENT)
+						  + len, MYF(MY_WME));
+    if (!e) 
+    {
+      fprintf(stderr, "Internal memory allocation error\n");
+      exit(1);
+    }
+    e->key= (char*)e + sizeof(TABLE_RULE_ENT);
+    e->key_len= len;
+    memcpy(e->key, argument, len);
+
+    if (!ignore_table_inited)
+      init_table_rule_hash(&ignore_table, &ignore_table_inited);
+    
+    if(my_hash_insert(&ignore_table, (byte*)e))
+    {
+      fprintf(stderr, "Internal hash insert error\n");
+      exit(1);
+    }
+    break;
+  }
   case (int) OPT_COMPATIBLE:
     {  
       char buff[255];
@@ -1946,6 +2019,15 @@ static int init_dumping(char *database)
 } /* init_dumping */
 
 
+my_bool include_table(byte* hash_key, uint len)
+{
+  if (ignore_table_inited &&
+      hash_search(&ignore_table, (byte*) hash_key, len))
+    return FALSE;
+
+  return TRUE;
+}
+
 
 static int dump_all_tables_in_db(char *database)
 {
@@ -1953,6 +2035,12 @@ static int dump_all_tables_in_db(char *database)
   uint numrows;
   char table_buff[NAME_LEN*2+3];
 
+  char hash_key[2*NAME_LEN+2];  /* "db.tablename" */
+  char *afterdot;
+
+  afterdot= strmov(hash_key, database);
+  *afterdot++= '.';
+
   if (init_dumping(database))
     return 1;
   if (opt_xml)
@@ -1961,7 +2049,7 @@ static int dump_all_tables_in_db(char *database)
   {
     DYNAMIC_STRING query;
     init_dynamic_string(&query, "LOCK TABLES ", 256, 1024);
-    for (numrows=0 ; (table = getTableName(1)) ; numrows++)
+    for (numrows= 0 ; (table= getTableName(1)) ; numrows++)
     {
       dynstr_append(&query, quote_name(table, table_buff, 1));
       dynstr_append(&query, " READ /*!32311 LOCAL */,");
@@ -1977,13 +2065,17 @@ static int dump_all_tables_in_db(char *database)
       DBerror(sock, "when doing refresh");
            /* We shall continue here, if --force was given */
   }
-  while ((table = getTableName(0)))
+  while ((table= getTableName(0)))
   {
-    numrows = getTableStructure(table, database);
-    if (!dFlag && numrows > 0)
-      dumpTable(numrows,table);
-    my_free(order_by, MYF(MY_ALLOW_ZERO_PTR));
-    order_by= 0;
+    char *end= strmov(afterdot, table);
+    if (include_table(hash_key, end - hash_key))
+    {
+      numrows = getTableStructure(table, database);
+      if (!dFlag && numrows > 0)
+	dumpTable(numrows,table);
+      my_free(order_by, MYF(MY_ALLOW_ZERO_PTR));
+      order_by= 0;
+    }
   }
   if (opt_xml)
   {
diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result
index 57e04d38fc193266f94bf798a84bf4a9c4832911..623bd2a0f3c0a5dcd3021d3a5d180bd04d140c24 100644
--- a/mysql-test/r/mysqldump.result
+++ b/mysql-test/r/mysqldump.result
@@ -480,3 +480,36 @@ UNLOCK TABLES;
 /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
 
 DROP TABLE t1;
+CREATE TABLE t1 (a int);
+CREATE TABLE t2 (a int);
+INSERT INTO t1 VALUES (1),(2),(3);
+INSERT INTO t2 VALUES (4),(5),(6);
+
+/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
+/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
+/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
+/*!40101 SET NAMES utf8 */;
+/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
+/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
+/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE="NO_AUTO_VALUE_ON_ZERO" */;
+DROP TABLE IF EXISTS `t2`;
+CREATE TABLE `t2` (
+  `a` int(11) default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1;
+
+
+/*!40000 ALTER TABLE `t2` DISABLE KEYS */;
+LOCK TABLES `t2` WRITE;
+INSERT INTO `t2` VALUES (4),(5),(6);
+UNLOCK TABLES;
+/*!40000 ALTER TABLE `t2` ENABLE KEYS */;
+
+/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
+/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
+/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
+/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
+/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
+/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
+
+DROP TABLE t1;
+DROP TABLE t2;
diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test
index 07b33689196175b2f2648b1e4c4046da3b23957e..255ae50a8ca5d922e3ac9eb5714926295682dd56 100644
--- a/mysql-test/t/mysqldump.test
+++ b/mysql-test/t/mysqldump.test
@@ -153,3 +153,15 @@ INSERT INTO t1  VALUES (_latin1 '
 --exec $MYSQL_DUMP --character-sets-dir=$CHARSETSDIR --skip-comments --default-character-set=cp850 --compatible=mysql323 test t1
 --exec $MYSQL_DUMP --character-sets-dir=$CHARSETSDIR --skip-comments --default-character-set=utf8 --compatible=mysql323 test t1
 DROP TABLE t1;
+
+#
+# WL #2319: Exclude Tables from dump
+#
+
+CREATE TABLE t1 (a int);
+CREATE TABLE t2 (a int);
+INSERT INTO t1 VALUES (1),(2),(3);
+INSERT INTO t2 VALUES (4),(5),(6);
+--exec $MYSQL_DUMP --skip-comments --ignore-table=test.t1 test
+DROP TABLE t1;
+DROP TABLE t2;