diff --git a/include/i18n/en_US/sequence.yaml b/include/i18n/en_US/sequence.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..bb502c3526c287280a2fe664419989e26c9307ef
--- /dev/null
+++ b/include/i18n/en_US/sequence.yaml
@@ -0,0 +1,23 @@
+#
+# Sequences installed with the system
+#
+# Fields:
+# id:           PK
+# name:         Name of the sequence
+# next:         Next value of the sequence
+# padding:      Padding character
+# increment:    Distance between two numbers of the sequence
+# flags:        Bitmask of flag settings. Currently known values are
+#               INTERNAL:=0x0001 (restrict delete)
+#
+---
+# ID:1 is reserved for upgrades. When transitioning to osTicket 1.10, the
+# sequence ID:1 will be configured to start counting from the current
+# MAX(ticket.ticket_id). The upgrade will miss this step if there is no
+# sequence with ID:1
+- id: 1
+  name: "General Tickets"
+  next: 1
+  padding: '0'
+  increment: 1
+  flags: 1
diff --git a/include/upgrader/streams/core/8f99b8bf-00000000.patch.sql b/include/upgrader/streams/core/8f99b8bf-00000000.patch.sql
new file mode 100644
index 0000000000000000000000000000000000000000..d03e6066b6ef3c7373da1aa9ec17fd36213476d3
--- /dev/null
+++ b/include/upgrader/streams/core/8f99b8bf-00000000.patch.sql
@@ -0,0 +1,48 @@
+/**
+ * @version v1.10.0
+ * @signature 00000000000000000000000000000000
+ * @title Custom Ticket Numbers
+ *
+ * This patch adds support for ticket number sequences to the database
+ * rather than the original implementation which had support for generating
+ * random numbers or using the database-created ticket_id value.
+ *
+ * This script will also migrate the previous settings, namely the
+ * use_random_ids config settings to the new system.
+ */
+
+DROP TABLE IF EXISTS `%TABLE_PREFIX%sequence`;
+CREATE TABLE `%TABLE_PREFIX%sequence` (
+  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
+  `name` varchar(64) DEFAULT NULL,
+  `flags` int(10) unsigned DEFAULT NULL,
+  `next` bigint(20) unsigned NOT NULL DEFAULT '1',
+  `increment` int(11) DEFAULT '1',
+  `padding` char(1) DEFAULT '0',
+  `updated` datetime NOT NULL,
+  PRIMARY KEY (`id`)
+-- InnoDB is intended here because transaction support is required for row
+-- locking
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+SET @random = (SELECT `value` FROM `%TABLE_PREFIX%config`
+    WHERE `namespace` = 'core' AND `key` = 'use_random_ids');
+
+-- Sequence (id=1) will be loaded in the task file
+INSERT INTO `%TABLE_PREFIX%config` (`namespace`, `key`, `value`)
+    VALUES
+    ('core', 'number_format', CASE WHEN @random THEN '######' ELSE '#' END),
+    ('core', 'sequence_id', CASE WHEN @random THEN 0 ELSE 1 END);
+
+DELETE FROM `%TABLE_PREFIX%config`
+WHERE `namespace`='core' AND `key` = 'use_random_ids';
+
+ALTER TABLE `%TABLE_PREFIX%help_topic`
+  ADD `flags` int(10) unsigned DEFAULT '0' AFTER `noautoresp`,
+  ADD `sequence_id` int(10) unsigned NOT NULL DEFAULT '0' AFTER `form_id`,
+  ADD `number_format` varchar(32) DEFAULT NULL AFTER `topic`;
+
+-- Finished with patch
+UPDATE `%TABLE_PREFIX%config`
+    SET `value` = '00000000000000000000000000000000'
+    WHERE `key` = 'schema_signature' AND `namespace` = 'core';
diff --git a/include/upgrader/streams/core/8f99b8bf-00000000.task.php b/include/upgrader/streams/core/8f99b8bf-00000000.task.php
new file mode 100644
index 0000000000000000000000000000000000000000..4644062a3c78f951e442d8393efe66d54d77a6ab
--- /dev/null
+++ b/include/upgrader/streams/core/8f99b8bf-00000000.task.php
@@ -0,0 +1,25 @@
+<?php
+
+/*
+ * Loads the initial sequence from the inital data files
+ */
+
+class SequenceLoader extends MigrationTask {
+    var $description = "Loading initial data for sequences";
+
+    function run($max_time) {
+        $i18n = new Internationalization('en_US');
+        $sequences = $i18n->getTemplate('sequence.yaml')->getData();
+        foreach ($sequences as $s) {
+            Sequence::create($s);
+            $s->save();
+        }
+        db_query('UPDATE '.SEQUENCE_TABLE.' SET `next`= '
+            .'(SELECT MAX(ticket_id) FROM '.TICKET_TABLE.') '
+            .'WHERE `id`=1');
+    }
+}
+
+return 'SequenceLoader';
+
+?>
diff --git a/setup/inc/streams/core/install-mysql.sql b/setup/inc/streams/core/install-mysql.sql
index 20c3dc3460c7cb3f323d1f6425e0844d9b6ffa3d..4b4350ccc732a13c795fa982af3ac873b9ecff5d 100644
--- a/setup/inc/streams/core/install-mysql.sql
+++ b/setup/inc/streams/core/install-mysql.sql
@@ -61,6 +61,20 @@ CREATE TABLE IF NOT EXISTS `%TABLE_PREFIX%faq_topic` (
   PRIMARY KEY  (`faq_id`,`topic_id`)
 ) DEFAULT CHARSET=utf8;
 
+DROP TABLE IF EXISTS `%TABLE_PREFIX%sequence`;
+CREATE TABLE `%TABLE_PREFIX%sequence` (
+  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
+  `name` varchar(64) DEFAULT NULL,
+  `flags` int(10) unsigned DEFAULT NULL,
+  `next` bigint(20) unsigned NOT NULL DEFAULT '1',
+  `increment` int(11) DEFAULT '1',
+  `padding` char(1) DEFAULT '0',
+  `updated` datetime NOT NULL,
+  PRIMARY KEY (`id`)
+-- InnoDB is intended here because transaction support is required for row
+-- locking
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
 DROP TABLE IF EXISTS `%TABLE_PREFIX%sla`;
 CREATE TABLE `%TABLE_PREFIX%sla` (
   `id` int(11) unsigned NOT NULL auto_increment,
@@ -404,6 +418,7 @@ CREATE TABLE `%TABLE_PREFIX%help_topic` (
   `isactive` tinyint(1) unsigned NOT NULL default '1',
   `ispublic` tinyint(1) unsigned NOT NULL default '1',
   `noautoresp` tinyint(3) unsigned NOT NULL default '0',
+  `flags` int(10) unsigned DEFAULT '0',
   `priority_id` tinyint(3) unsigned NOT NULL default '0',
   `dept_id` tinyint(3) unsigned NOT NULL default '0',
   `staff_id` int(10) unsigned NOT NULL default '0',
@@ -411,8 +426,10 @@ CREATE TABLE `%TABLE_PREFIX%help_topic` (
   `sla_id` int(10) unsigned NOT NULL default '0',
   `page_id` int(10) unsigned NOT NULL default '0',
   `form_id` int(10) unsigned NOT NULL default '0',
+  `sequence_id` int(10) unsigned NOT NULL DEFAULT '0',
   `sort` int(10) unsigned NOT NULL default '0',
   `topic` varchar(32) NOT NULL default '',
+  `number_format` varchar(32) DEFAULT NULL,
   `notes` text,
   `created` datetime NOT NULL,
   `updated` datetime NOT NULL,