diff --git a/include/ma_common.h b/include/ma_common.h
index c598136..a583f10 100644
--- a/include/ma_common.h
+++ b/include/ma_common.h
@@ -113,3 +113,9 @@ struct st_mariadb_extension {
     (a)->options.extension->key : 0
 
 #endif
+
+
+typedef struct st_mariadb_field_extension
+{
+  MARIADB_CONST_STRING metadata[MARIADB_FIELD_METADATA_LAST+1]; /* 10.5 */
+} MA_FIELD_EXTENSION;
diff --git a/include/ma_priv.h b/include/ma_priv.h
index 7d30094..5ee083c 100644
--- a/include/ma_priv.h
+++ b/include/ma_priv.h
@@ -24,8 +24,27 @@
 
 void free_rows(MYSQL_DATA *cur);
 int ma_multi_command(MYSQL *mysql, enum enum_multi_status status);
-MYSQL_FIELD * unpack_fields(MYSQL_DATA *data,
+MYSQL_FIELD * unpack_fields(const MYSQL *mysql, MYSQL_DATA *data,
                             MA_MEM_ROOT *alloc,uint fields,
                             my_bool default_value);
 
+static inline my_bool ma_has_extended_type_info(const MYSQL *mysql)
+{
+  return ((mysql->extension->mariadb_server_capabilities << 32) &
+          MARIADB_CLIENT_EXTENDED_TYPE_INFO) != 0;
+}
+
+static inline uint ma_extended_type_info_rows(const MYSQL *mysql)
+{
+  return ma_has_extended_type_info(mysql) ? 1 : 0;
+}
+
+static inline uint ma_result_set_rows(const MYSQL *mysql)
+{
+  return ma_has_extended_type_info(mysql) ? 9 : 8;
+}
+
+MA_FIELD_EXTENSION *ma_field_extension_deep_dup(MA_MEM_ROOT *memroot,
+                                                const MA_FIELD_EXTENSION *from);
+
 #endif
diff --git a/include/mariadb_com.h b/include/mariadb_com.h
index 9a5da28..aafa2a5 100644
--- a/include/mariadb_com.h
+++ b/include/mariadb_com.h
@@ -170,13 +170,16 @@ enum enum_server_command
 #define MARIADB_CLIENT_PROGRESS (1ULL << 32)
 #define MARIADB_CLIENT_COM_MULTI (1ULL << 33)
 #define MARIADB_CLIENT_STMT_BULK_OPERATIONS (1ULL << 34)
+/* support of extended data type/format information, since 10.5.0 */
+#define MARIADB_CLIENT_EXTENDED_TYPE_INFO (1ULL << 35)
 
 #define IS_MARIADB_EXTENDED_SERVER(mysql)\
         !(mysql->server_capabilities & CLIENT_MYSQL)
 
 #define MARIADB_CLIENT_SUPPORTED_FLAGS (MARIADB_CLIENT_PROGRESS |\
                                        MARIADB_CLIENT_COM_MULTI |\
-                                       MARIADB_CLIENT_STMT_BULK_OPERATIONS)
+                                       MARIADB_CLIENT_STMT_BULK_OPERATIONS|\
+                                       MARIADB_CLIENT_EXTENDED_TYPE_INFO)
 
 #define CLIENT_SUPPORTED_FLAGS  (CLIENT_MYSQL |\
                                  CLIENT_FOUND_ROWS |\
diff --git a/include/mysql.h b/include/mysql.h
index dcaf316..476f5c1 100644
--- a/include/mysql.h
+++ b/include/mysql.h
@@ -61,6 +61,14 @@ typedef int my_socket;
 #include "ma_list.h"
 #include "mariadb_ctype.h"
 
+
+typedef struct st_ma_const_string
+{
+  const char *str;
+  size_t length;
+} MARIADB_CONST_STRING;
+
+
 #ifndef ST_MA_USED_MEM_DEFINED
 #define ST_MA_USED_MEM_DEFINED
   typedef struct st_ma_used_mem {   /* struct for once_alloc */
@@ -383,6 +391,20 @@ typedef struct
   void *extension;
 } MYSQL_PARAMETERS;
 
+
+enum mariadb_field_metadata_attr_t
+{
+  MARIADB_FIELD_METADATA_DATA_TYPE_NAME= 1,
+  MARIADB_FIELD_METADATA_FORMAT_NAME= 2
+};
+
+#define MARIADB_FIELD_METADATA_LAST MARIADB_FIELD_METADATA_FORMAT_NAME
+
+
+MARIADB_CONST_STRING
+  mariadb_field_metadata_attr(const MYSQL_FIELD *field,
+                              enum mariadb_field_metadata_attr_t type);
+
 #ifndef _mysql_time_h_
 enum enum_mysql_timestamp_type
 {
diff --git a/libmariadb/mariadb_lib.c b/libmariadb/mariadb_lib.c
index 1063f14..4c5536e 100644
--- a/libmariadb/mariadb_lib.c
+++ b/libmariadb/mariadb_lib.c
@@ -751,6 +751,79 @@ my_bool _mariadb_set_conf_option(MYSQL *mysql, const char *config_option, const
   return 1;
 }
 
+
+static MARIADB_CONST_STRING null_const_string= {0,0};
+
+/***************************************************************************
+** Allocate a string copy on memroot
+***************************************************************************/
+static MARIADB_CONST_STRING ma_const_string_copy_root(MA_MEM_ROOT *memroot,
+                                                      const char *str,
+                                                      size_t length)
+{
+  MARIADB_CONST_STRING res;
+  if (!str || !(res.str= ma_memdup_root(memroot, str, length)))
+    return null_const_string;
+  res.length= length;
+  return res;
+}
+
+
+/***************************************************************************
+** Allocate and initialize MA_FIELD_EXTENSION
+***************************************************************************/
+MA_FIELD_EXTENSION *new_ma_field_extension(MA_MEM_ROOT *memroot)
+{
+  MA_FIELD_EXTENSION *ext= ma_alloc_root(memroot, sizeof(MA_FIELD_EXTENSION));
+  if (ext)
+    memset((void *) ext, 0, sizeof(*ext));
+  return ext;
+}
+
+
+/***************************************************************************
+** Populate field extension from a type info packet
+***************************************************************************/
+
+static void ma_field_extension_init_type_info(MA_MEM_ROOT *memroot,
+                                              MA_FIELD_EXTENSION *ext,
+                                              const char *ptr, size_t length)
+{
+  const char *end= ptr + length;
+  for ( ;  ptr < end; )
+  {
+    uint itype= (uchar) *ptr++;
+    uint len= (uchar) *ptr++;
+    if (ptr + len > end  || len > 127)
+      break; /*Badly encoded data*/
+    if (itype <= 127 && itype <= MARIADB_FIELD_METADATA_LAST)
+      ext->metadata[itype]= ma_const_string_copy_root(memroot, ptr, len);
+    ptr+= len;
+  }
+}
+
+
+/***************************************************************************
+** Allocate a field extension deep copy
+***************************************************************************/
+
+MA_FIELD_EXTENSION *ma_field_extension_deep_dup(MA_MEM_ROOT *memroot,
+                                                const MA_FIELD_EXTENSION *from)
+{
+  MA_FIELD_EXTENSION *ext= new_ma_field_extension(memroot);
+  uint i;
+  if (!ext)
+    return NULL;
+  for (i= 0; i < MARIADB_FIELD_METADATA_LAST; i++)
+  {
+    if (from->metadata[i].str)
+      ext->metadata[i]= ma_const_string_copy_root(memroot,
+                                                  from->metadata[i].str,
+                                                  from->metadata[i].length);
+  }
+  return ext;
+}
+
 /***************************************************************************
 ** Change field rows to field structs
 ***************************************************************************/
@@ -771,7 +844,8 @@ static size_t rset_field_offsets[]= {
 };
 
 MYSQL_FIELD *
-unpack_fields(MYSQL_DATA *data,MA_MEM_ROOT *alloc,uint fields,
+unpack_fields(const MYSQL *mysql,
+              MYSQL_DATA *data, MA_MEM_ROOT *alloc, uint fields,
 	      my_bool default_value)
 {
   MYSQL_ROWS	*row;
@@ -804,7 +878,20 @@ unpack_fields(MYSQL_DATA *data,MA_MEM_ROOT *alloc,uint fields,
       }
     }
 
-    p= (char *)row->data[6];
+    field->extension= NULL;
+    if (ma_has_extended_type_info(mysql))
+    {
+      if (row->data[i+1] - row->data[i] > 1)
+      {
+        size_t len= row->data[i+1] - row->data[i] - 1;
+        MA_FIELD_EXTENSION *ext= new_ma_field_extension(alloc);
+        if ((field->extension= ext))
+          ma_field_extension_init_type_info(alloc, ext, row->data[i], len);
+      }
+      i++;
+    }
+
+    p= (char *)row->data[i];
     /* filler */
     field->charsetnr= uint2korr(p);
     p+= 2;
@@ -823,10 +910,11 @@ unpack_fields(MYSQL_DATA *data,MA_MEM_ROOT *alloc,uint fields,
     if (INTERNAL_NUM_FIELD(field))
       field->flags|= NUM_FLAG;
 
+    i++;
     /* This is used by deprecated function mysql_list_fields only,
        however the reported length is not correct, so we always zero it */
-    if (default_value && row->data[7])
-      field->def=ma_strdup_root(alloc,(char*) row->data[7]);
+    if (default_value && row->data[i])
+      field->def=ma_strdup_root(alloc,(char*) row->data[i]);
     else
       field->def=0;
     field->def_length= 0;
@@ -2193,9 +2281,10 @@ get_info:
     mysql->server_status|= SERVER_STATUS_IN_TRANS;
 
   mysql->extra_info= net_field_length_ll(&pos); /* Maybe number of rec */
-  if (!(fields=mysql->methods->db_read_rows(mysql,(MYSQL_FIELD*) 0,8)))
+  if (!(fields=mysql->methods->db_read_rows(mysql,(MYSQL_FIELD*) 0,
+                                            ma_result_set_rows(mysql))))
     return(-1);
-  if (!(mysql->fields=unpack_fields(fields,&mysql->field_alloc,
+  if (!(mysql->fields=unpack_fields(mysql, fields, &mysql->field_alloc,
 				    (uint) field_count, 1)))
     return(-1);
   mysql->status=MYSQL_STATUS_GET_RESULT;
@@ -2345,6 +2434,21 @@ mysql_fetch_field(MYSQL_RES *result)
   return &result->fields[result->current_field++];
 }
 
+
+/**************************************************************************
+** Return mysql field metadata
+**************************************************************************/
+MARIADB_CONST_STRING
+mariadb_field_metadata_attr(const MYSQL_FIELD *field,
+                            enum mariadb_field_metadata_attr_t type)
+{
+  MA_FIELD_EXTENSION *ext= (MA_FIELD_EXTENSION*) field->extension;
+  if (!ext || type > MARIADB_FIELD_METADATA_LAST)
+    return null_const_string;
+  return ext->metadata[type];
+}
+
+
 /**************************************************************************
 **  Return next row of the query results
 **************************************************************************/
@@ -2513,7 +2617,8 @@ mysql_list_fields(MYSQL *mysql, const char *table, const char *wild)
   length= snprintf(buff, 128, "%s%c%s", table, '\0', wild ? wild : "");
 
   if (ma_simple_command(mysql, COM_FIELD_LIST,buff,length,1,0) ||
-      !(query = mysql->methods->db_read_rows(mysql,(MYSQL_FIELD*) 0,8)))
+      !(query = mysql->methods->db_read_rows(mysql,(MYSQL_FIELD*) 0,
+                                             ma_result_set_rows(mysql))))
     return(NULL);
 
   free_old_query(mysql);
@@ -2526,7 +2631,7 @@ mysql_list_fields(MYSQL *mysql, const char *table, const char *wild)
   mysql->fields=0;
   result->eof=1;
   result->field_count = (uint) query->rows;
-  result->fields= unpack_fields(query,&result->field_alloc,
+  result->fields= unpack_fields(mysql, query, &result->field_alloc,
 				result->field_count, 1);
   if (result->fields)
     return(result);
@@ -2552,8 +2657,8 @@ mysql_list_processes(MYSQL *mysql)
   field_count=(uint) net_field_length(&pos);
   if (!(fields = mysql->methods->db_read_rows(mysql,(MYSQL_FIELD*) 0,5)))
     return(NULL);
-  if (!(mysql->fields=unpack_fields(fields, &mysql->field_alloc,
-                                    field_count, 0)))
+  if (!(mysql->fields= unpack_fields(mysql, fields, &mysql->field_alloc,
+                                     field_count, 0)))
     return(NULL);
   mysql->status=MYSQL_STATUS_GET_RESULT;
   mysql->field_count=field_count;
diff --git a/libmariadb/mariadb_stmt.c b/libmariadb/mariadb_stmt.c
index 86e39ca..433e495 100644
--- a/libmariadb/mariadb_stmt.c
+++ b/libmariadb/mariadb_stmt.c
@@ -1581,7 +1581,8 @@ my_bool mthd_stmt_get_param_metadata(MYSQL_STMT *stmt)
 {
   MYSQL_DATA *result;
 
-  if (!(result= stmt->mysql->methods->db_read_rows(stmt->mysql, (MYSQL_FIELD *)0, 7)))
+  if (!(result= stmt->mysql->methods->db_read_rows(stmt->mysql, (MYSQL_FIELD *)0,
+                                                   7 + ma_extended_type_info_rows(stmt->mysql))))
     return(1);
 
   free_rows(result);
@@ -1593,9 +1594,10 @@ my_bool mthd_stmt_get_result_metadata(MYSQL_STMT *stmt)
   MYSQL_DATA *result;
   MA_MEM_ROOT *fields_ma_alloc_root= &((MADB_STMT_EXTENSION *)stmt->extension)->fields_ma_alloc_root;
 
-  if (!(result= stmt->mysql->methods->db_read_rows(stmt->mysql, (MYSQL_FIELD *)0, 7)))
+  if (!(result= stmt->mysql->methods->db_read_rows(stmt->mysql, (MYSQL_FIELD *)0,
+                                                   7 + ma_extended_type_info_rows(stmt->mysql))))
     return(1);
-  if (!(stmt->fields= unpack_fields(result,fields_ma_alloc_root,
+  if (!(stmt->fields= unpack_fields(stmt->mysql, result, fields_ma_alloc_root,
           stmt->field_count, 0)))
     return(1);
   return(0);
@@ -1836,6 +1838,11 @@ static int madb_alloc_stmt_fields(MYSQL_STMT *stmt)
       stmt->fields[i].decimals= stmt->mysql->fields[i].decimals;
       stmt->fields[i].charsetnr= stmt->mysql->fields[i].charsetnr;
       stmt->fields[i].max_length= stmt->mysql->fields[i].max_length;
+      stmt->fields[i].extension=
+                stmt->mysql->fields[i].extension ?
+                ma_field_extension_deep_dup(fields_ma_alloc_root,
+                                            stmt->mysql->fields[i].extension) :
+                NULL;
     }
     if (!(stmt->bind= (MYSQL_BIND *)ma_alloc_root(fields_ma_alloc_root, stmt->field_count * sizeof(MYSQL_BIND))))
     {
@@ -1912,7 +1919,6 @@ int stmt_read_execute_response(MYSQL_STMT *stmt)
         /* since  all pointers will be incorrect if another statement will
            be executed, so we need to allocate memory and copy the
            information */
-        stmt->fields[i].extension= 0; /* not in use yet */
         if (mysql->fields[i].db)
           stmt->fields[i].db= ma_strdup_root(fields_ma_alloc_root, mysql->fields[i].db);
         if (mysql->fields[i].table)
@@ -1927,6 +1933,11 @@ int stmt_read_execute_response(MYSQL_STMT *stmt)
           stmt->fields[i].catalog= ma_strdup_root(fields_ma_alloc_root, mysql->fields[i].catalog);
         if (mysql->fields[i].def)
           stmt->fields[i].def= ma_strdup_root(fields_ma_alloc_root, mysql->fields[i].def);
+        stmt->fields[i].extension=
+                mysql->fields[i].extension ?
+                ma_field_extension_deep_dup(fields_ma_alloc_root,
+                                            mysql->fields[i].extension) :
+                NULL;
       }
     }
 
