diff --git a/mysql-test/std_data/bug48633.ARM b/mysql-test/std_data/bug48633.ARM
new file mode 100644
index 00000000000..5a46ddacc3a
Binary files /dev/null and b/mysql-test/std_data/bug48633.ARM differ
diff --git a/mysql-test/std_data/bug48633.ARZ b/mysql-test/std_data/bug48633.ARZ
new file mode 100644
index 00000000000..0aa85c690e5
Binary files /dev/null and b/mysql-test/std_data/bug48633.ARZ differ
diff --git a/mysql-test/std_data/bug48633.frm b/mysql-test/std_data/bug48633.frm
new file mode 100644
index 00000000000..5c2a8a688b7
Binary files /dev/null and b/mysql-test/std_data/bug48633.frm differ
diff --git a/mysql-test/suite/archive/archive.result b/mysql-test/suite/archive/archive.result
index b187c216120..b92018fba8b 100644
--- a/mysql-test/suite/archive/archive.result
+++ b/mysql-test/suite/archive/archive.result
@@ -12729,7 +12729,6 @@ id	id	name	name
 1	1	a	b
 2	2	a	b
 DROP TABLE t1,t2;
-flush tables;
 SHOW CREATE TABLE t1;
 Table	Create Table
 t1	CREATE TABLE `t1` (
@@ -12741,7 +12740,7 @@ col1	col2
 INSERT INTO t1 (col1, col2) VALUES (1, "value");
 REPAIR TABLE t1;
 Table	Op	Msg_type	Msg_text
-test.t1	repair	error	Corrupt
+test.t1	repair	status	OK
 DROP TABLE t1;
 #
 # Ensure that TRUNCATE fails for non-empty archive tables.
@@ -12787,6 +12786,62 @@ a	b	c	d	e	f
 DROP TABLE t1;
 SET sort_buffer_size=DEFAULT;
 #
+# BUG#11756687 - 48633: ARCHIVE TABLES ARE NOT UPGRADEABLE
+#
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `a` int(11) DEFAULT NULL,
+  `b` text,
+  `c` varchar(255) DEFAULT NULL,
+  `d` blob,
+  `e` blob
+) ENGINE=ARCHIVE DEFAULT CHARSET=latin1
+SELECT * FROM t1;
+a	b	c	d	e
+1	text	varchar	blob1	blob2
+2	text	varchar	blob1	blob2
+SELECT * FROM t1;
+a	b	c	d	e
+1	text	varchar	blob1	blob2
+2	text	varchar	blob1	blob2
+FLUSH TABLE t1;
+SELECT * FROM t1;
+a	b	c	d	e
+1	text	varchar	blob1	blob2
+2	text	varchar	blob1	blob2
+CHECK TABLE t1;
+Table	Op	Msg_type	Msg_text
+test.t1	check	error	Table upgrade required. Please do "REPAIR TABLE `t1`" or dump/reload to fix it!
+SELECT * FROM t1;
+a	b	c	d	e
+1	text	varchar	blob1	blob2
+2	text	varchar	blob1	blob2
+INSERT INTO t1 VALUES(3, 'text', 'varchar', 'blob1', 'blob2');
+SELECT * FROM t1;
+a	b	c	d	e
+1	text	varchar	blob1	blob2
+2	text	varchar	blob1	blob2
+3	text	varchar	blob1	blob2
+FLUSH TABLE t1;
+SELECT * FROM t1;
+a	b	c	d	e
+1	text	varchar	blob1	blob2
+2	text	varchar	blob1	blob2
+3	text	varchar	blob1	blob2
+REPAIR TABLE t1;
+Table	Op	Msg_type	Msg_text
+test.t1	repair	status	OK
+SELECT * FROM t1;
+a	b	c	d	e
+1	text	varchar	blob1	blob2
+2	text	varchar	blob1	blob2
+3	text	varchar	blob1	blob2
+CHECK TABLE t1;
+Table	Op	Msg_type	Msg_text
+test.t1	check	status	OK
+DROP TABLE t1;
+#
 # BUG#11758979 - 51252: ARCHIVE TABLES STILL FAIL UNDER STRESS
 #                TESTS: CRASH, CORRUPTION, 4G MEMOR
 # (to be executed with valgrind)
diff --git a/mysql-test/suite/archive/archive.test b/mysql-test/suite/archive/archive.test
index 5d96aa256fb..81a73683541 100644
--- a/mysql-test/suite/archive/archive.test
+++ b/mysql-test/suite/archive/archive.test
@@ -12,6 +12,7 @@ DROP TABLE if exists t1,t2,t3,t4,t5,t6;
 --enable_warnings
 
 SET storage_engine=ARCHIVE;
+let $MYSQLD_DATADIR= `SELECT @@datadir`;
 
 CREATE TABLE t1 (
   Period smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL,
@@ -1643,12 +1644,6 @@ DROP TABLE t1,t2;
 #
 # BUG#47012 archive tables are not upgradeable, and server crashes on any access
 #
-let $MYSQLD_DATADIR= `SELECT @@datadir`;
-
-# Remove files to handle possible restart of test
-flush tables;
-remove_files_wildcard $MYSQLD_DATADIR/test t1.*;
-
 copy_file std_data/bug47012.frm $MYSQLD_DATADIR/test/t1.frm;
 copy_file std_data/bug47012.ARZ $MYSQLD_DATADIR/test/t1.ARZ;
 copy_file std_data/bug47012.ARM $MYSQLD_DATADIR/test/t1.ARM;
@@ -1661,7 +1656,6 @@ INSERT INTO t1 (col1, col2) VALUES (1, "value");
 
 REPAIR TABLE t1;
 DROP TABLE t1;
-remove_file $MYSQLD_DATADIR/test/t1.ARM;
 
 --echo #
 --echo # Ensure that TRUNCATE fails for non-empty archive tables.
@@ -1711,6 +1705,36 @@ SELECT * FROM t1 ORDER BY f LIMIT 1;
 DROP TABLE t1;
 SET sort_buffer_size=DEFAULT;
 
+--echo #
+--echo # BUG#11756687 - 48633: ARCHIVE TABLES ARE NOT UPGRADEABLE
+--echo #
+copy_file std_data/bug48633.frm $MYSQLD_DATADIR/test/t1.frm;
+copy_file std_data/bug48633.ARZ $MYSQLD_DATADIR/test/t1.ARZ;
+copy_file std_data/bug48633.ARM $MYSQLD_DATADIR/test/t1.ARM;
+SHOW CREATE TABLE t1;
+# Test first table scan
+SELECT * FROM t1;
+# Test second table scan
+SELECT * FROM t1;
+# Test table close
+FLUSH TABLE t1;
+SELECT * FROM t1;
+# Test check
+CHECK TABLE t1;
+SELECT * FROM t1;
+# Test insert
+INSERT INTO t1 VALUES(3, 'text', 'varchar', 'blob1', 'blob2');
+SELECT * FROM t1;
+# Test table close after insert
+FLUSH TABLE t1;
+SELECT * FROM t1;
+# Test repair
+REPAIR TABLE t1;
+SELECT * FROM t1;
+# Test check table after upgrade
+CHECK TABLE t1;
+DROP TABLE t1;
+
 --echo #
 --echo # BUG#11758979 - 51252: ARCHIVE TABLES STILL FAIL UNDER STRESS
 --echo #                TESTS: CRASH, CORRUPTION, 4G MEMOR
diff --git a/storage/archive/azio.c b/storage/archive/azio.c
index 4519d15cefc..c1efe19e91f 100644
--- a/storage/archive/azio.c
+++ b/storage/archive/azio.c
@@ -77,6 +77,7 @@ int az_open (azio_stream *s, const char *path, int Flags, File fd)
   s->version = (unsigned char)az_magic[1]; /* this needs to be a define to version */
   s->minor_version= (unsigned char) az_magic[2]; /* minor version */
   s->dirty= AZ_STATE_CLEAN;
+  s->start= 0;
 
   /*
     We do our own version of append by nature. 
@@ -186,6 +187,9 @@ int write_header(azio_stream *s)
   char buffer[AZHEADER_SIZE + AZMETA_BUFFER_SIZE];
   char *ptr= buffer;
 
+  if (s->version == 1)
+    return 0;
+
   s->block_size= AZ_BUFSIZE_WRITE;
   s->version = (unsigned char)az_magic[1];
   s->minor_version = (unsigned char)az_magic[2];
@@ -308,9 +312,9 @@ void check_header(azio_stream *s)
   /* Peek ahead to check the gzip magic header */
   if ( s->stream.next_in[0] == gz_magic[0]  && s->stream.next_in[1] == gz_magic[1])
   {
+    read_header(s, s->stream.next_in);
     s->stream.avail_in -= 2;
     s->stream.next_in += 2;
-    s->version= (unsigned char)2;
 
     /* Check the rest of the gzip header */
     method = get_byte(s);
@@ -339,7 +343,8 @@ void check_header(azio_stream *s)
       for (len = 0; len < 2; len++) (void)get_byte(s);
     }
     s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;
-    s->start = my_tell(s->file, MYF(0)) - s->stream.avail_in;
+    if (!s->start)
+      s->start= my_tell(s->file, MYF(0)) - s->stream.avail_in;
   }
   else if ( s->stream.next_in[0] == az_magic[0]  && s->stream.next_in[1] == az_magic[1])
   {
@@ -401,9 +406,13 @@ void read_header(azio_stream *s, unsigned char *buffer)
   else if (buffer[0] == gz_magic[0]  && buffer[1] == gz_magic[1])
   {
     /*
-      Set version number to previous version (2).
+      Set version number to previous version (1).
     */
-    s->version= (unsigned char) 2;
+    s->version= 1;
+    s->auto_increment= 0;
+    s->frm_length= 0;
+    s->longest_row= 0;
+    s->shortest_row= 0;
   } else {
     /*
       Unknown version.
diff --git a/storage/archive/ha_archive.cc b/storage/archive/ha_archive.cc
index bb66d329de0..82f2513ad59 100644
--- a/storage/archive/ha_archive.cc
+++ b/storage/archive/ha_archive.cc
@@ -97,6 +97,11 @@
      inserts a lot faster, but would mean highly arbitrary reads.
 
     -Brian
+
+  Archive file format versions:
+  <5.1.5 - v.1
+  5.1.5-5.1.15 - v.2
+  >5.1.15 - v.3
 */
 
 
@@ -192,9 +197,11 @@ static void init_archive_psi_keys(void)
 
 /*
   We just implement one additional file extension.
+  ARM is here just to properly drop 5.0 tables.
 */
 static const char *ha_archive_exts[] = {
   ARZ,
+  ARM,
   NullS
 };
 
@@ -581,20 +588,13 @@ int ha_archive::open(const char *name, int mode, uint open_options)
   if (!share)
     DBUG_RETURN(rc);
 
- /*
-    Allow open on crashed table in repair mode only.
-    Block open on 5.0 ARCHIVE table. Though we have almost all
-    routines to access these tables, they were not well tested.
-    For now we have to refuse to open such table to avoid
-    potential data loss.
-  */
+  /* Allow open on crashed table in repair mode only. */
   switch (rc)
   {
   case 0:
     break;
   case HA_ERR_TABLE_DEF_CHANGED:
   case HA_ERR_CRASHED_ON_USAGE:
-  case HA_ERR_TABLE_NEEDS_UPGRADE:
     if (open_options & HA_OPEN_FOR_REPAIR)
     {
       rc= 0;
@@ -675,6 +675,17 @@ int ha_archive::frm_copy(azio_stream *src, azio_stream *dst)
   int rc= 0;
   uchar *frm_ptr;
 
+  if (!src->frm_length)
+  {
+    size_t frm_len;
+    if (!table_share->read_frm_image((const uchar**) &frm_ptr, &frm_len))
+    {
+      azwrite_frm(dst, frm_ptr, frm_len);
+      table_share->free_frm_image(frm_ptr);
+    }
+    return 0;
+  }
+
   if (!(frm_ptr= (uchar *) my_malloc(src->frm_length,
                                      MYF(MY_THREAD_SPECIFIC | MY_WME))))
     return HA_ERR_OUT_OF_MEM;
@@ -1639,19 +1650,13 @@ int ha_archive::info(uint flag)
 {
   DBUG_ENTER("ha_archive::info");
 
-  /* 
-    If dirty, we lock, and then reset/flush the data.
-    I found that just calling azflush() doesn't always work.
-  */
   mysql_mutex_lock(&share->mutex);
-  if (share->dirty == TRUE)
+  if (share->dirty)
   {
-    if (share->dirty == TRUE)
-    {
-      DBUG_PRINT("ha_archive", ("archive flushing out rows for scan"));
-      azflush(&(share->archive_write), Z_SYNC_FLUSH);
-      share->dirty= FALSE;
-    }
+    DBUG_PRINT("ha_archive", ("archive flushing out rows for scan"));
+    DBUG_ASSERT(share->archive_write_open);
+    azflush(&(share->archive_write), Z_SYNC_FLUSH);
+    share->dirty= FALSE;
   }
 
   /* 
@@ -1727,7 +1732,10 @@ int ha_archive::end_bulk_insert()
 {
   DBUG_ENTER("ha_archive::end_bulk_insert");
   bulk_insert= FALSE;
-  share->dirty= TRUE;
+  mysql_mutex_lock(&share->mutex);
+  if (share->archive_write_open)
+    share->dirty= true;
+  mysql_mutex_unlock(&share->mutex);
   DBUG_RETURN(0);
 }