diff --git a/docs/configuration.md b/docs/configuration.md
index 95a5abea958a85430acbc9266d8e19bb94f5cb7f..39f37c96be291e1fa9d8ec1d8b8cdf136d27d320 100644
--- a/docs/configuration.md
+++ b/docs/configuration.md
@@ -779,10 +779,13 @@ Obviously, you can't set repository or package file location with this method.
   <td>json</td>
   <td><pre>{
   "enabled": true,
-  "branchName": "{{branchPrefix}}docker-{{depNameSanitized}}-{{currentTag}}",
+  "branchName": "{{branchPrefix}}docker-{{depNameSanitized}}-{{newVersionMajor}}.x",
   "commitMessage": "Update {{depName}}:{{currentTag}} digest",
-  "prTitle": "Update Dockerfile image {{depName}}@{{currentTag}} digest",
+  "prTitle": "Update Dockerfile {{depName}} image tag to {{newTag}}",
   "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates Docker base image `{{depName}}@{{currentTag}}` to the latest digest (`{{newDigest}}`).\n\n{{#if schedule}}\n**Note**: This PR was created on a configured schedule (\"{{schedule}}\"{{#if timezone}} in timezone `{{timezone}}`{{/if}}) and will not receive updates outside those times.\n{{/if}}\n\n{{#if hasErrors}}\n\n---\n\n### Errors\n\nRenovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR.\n\n{{#each errors as |error|}}\n-   `{{error.depName}}`: {{error.message}}\n{{/each}}\n{{/if}}\n\n{{#if hasWarnings}}\n\n---\n\n### Warnings\n\nPlease make sure the following warnings are safe to ignore:\n\n{{#each warnings as |warning|}}\n-   `{{warning.depName}}`: {{warning.message}}\n{{/each}}\n{{/if}}\n\n---\n\nThis {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).",
+  "major": {"enabled": false},
+  "minor": {"enabled": false},
+  "patch": {"enabled": false},
   "pin": {
     "branchName": "{{branchPrefix}}docker-pin-{{depNameSanitized}}-{{currentTag}}",
     "prTitle": "Pin Dockerfile {{depName}}@{{currentTag}} image digest",
diff --git a/lib/api/docker.js b/lib/api/docker.js
index 196d0b9cb4f03a1d3873407b3e4104cf0394c5b8..52d10cbc69573933e9a659661918be02bd0c0e76 100644
--- a/lib/api/docker.js
+++ b/lib/api/docker.js
@@ -2,6 +2,7 @@ const got = require('got');
 
 module.exports = {
   getDigest,
+  getTags,
 };
 
 async function getDigest(name, tag, logger) {
@@ -31,3 +32,28 @@ async function getDigest(name, tag, logger) {
     return null;
   }
 }
+
+async function getTags(name, logger) {
+  const repository = name.includes('/') ? name : `library/${name}`;
+  try {
+    const authUrl = `https://auth.docker.io/token?service=registry.docker.io&scope=repository:${repository}:pull`;
+    logger.debug(`Obtaining docker registry token for ${repository}`);
+    const { token } = (await got(authUrl, { json: true })).body;
+    if (!token) {
+      logger.warn('Failed to obtain docker registry token');
+      return null;
+    }
+    logger.debug('Got docker registry token');
+    const url = `https://index.docker.io/v2/${repository}/tags/list?n=10000`;
+    const headers = {
+      Authorization: `Bearer ${token}`,
+      Accept: 'application/vnd.docker.distribution.manifest.v2+json',
+    };
+    const res = await got(url, { json: true, headers });
+    logger.debug({ tags: res.body.tags }, 'Got docker tags');
+    return res.body.tags;
+  } catch (err) {
+    logger.warn({ err, name }, 'Error getting docker image tags');
+    return null;
+  }
+}
diff --git a/lib/config/definitions.js b/lib/config/definitions.js
index ed3de2f8ad23b1effc785d687d3de92d43090e72..515ea056fb6601c33ab7235bc6ba8b9a1d170c7c 100644
--- a/lib/config/definitions.js
+++ b/lib/config/definitions.js
@@ -613,6 +613,9 @@ const options = [
       commitMessage: template('commitMessage', 'docker'),
       prTitle: template('prTitle', 'docker'),
       prBody: template('prBody', 'docker'),
+      major: { enabled: false },
+      minor: { enabled: false },
+      patch: { enabled: false },
       pin: {
         branchName: template('branchName', 'docker-pin'),
         prTitle: template('prTitle', 'docker-pin'),
diff --git a/lib/config/templates/docker/branch-name.hbs b/lib/config/templates/docker/branch-name.hbs
index 5a353edf92f4bb504e8bf38d03177a975adacf7f..817fd2300e0d65e97f5d2b0567a69adc81098cf7 100644
--- a/lib/config/templates/docker/branch-name.hbs
+++ b/lib/config/templates/docker/branch-name.hbs
@@ -1 +1 @@
-{{branchPrefix}}docker-{{depNameSanitized}}-{{currentTag}}
+{{branchPrefix}}docker-{{depNameSanitized}}-{{newVersionMajor}}.x
diff --git a/lib/config/templates/docker/pr-title.hbs b/lib/config/templates/docker/pr-title.hbs
index 9924b03b5856a83ea4be6cb342c6c3258cd9e9ec..70b872fedc5b8914af906b871eda5660537fd320 100644
--- a/lib/config/templates/docker/pr-title.hbs
+++ b/lib/config/templates/docker/pr-title.hbs
@@ -1 +1 @@
-Update Dockerfile image {{depName}}@{{currentTag}} digest
+Update Dockerfile {{depName}} image tag to {{newTag}}
diff --git a/lib/workers/package/docker.js b/lib/workers/package/docker.js
index f148442cb4b3136310c96d5159cdfa598eae55e3..fe021020516e1c2a6d3bd7f3dd2510a8efdf5f82 100644
--- a/lib/workers/package/docker.js
+++ b/lib/workers/package/docker.js
@@ -1,14 +1,17 @@
+const semver = require('semver');
 const dockerApi = require('../../api/docker');
+const versions = require('./versions');
+const compareVersions = require('compare-versions');
 
 module.exports = {
   renovateDockerImage,
 };
 
 async function renovateDockerImage(config) {
-  const { currentTag, logger } = config;
+  const { currentFrom, currentTag, logger } = config;
   const upgrades = [];
   if (config.pinDigests) {
-    logger.debug('Checking Docker pinDigests');
+    logger.debug('Checking docker pinDigests');
     const newDigest = await dockerApi.getDigest(
       config.depName,
       currentTag,
@@ -34,5 +37,87 @@ async function renovateDockerImage(config) {
       upgrades.push(upgrade);
     }
   }
+  if (currentTag) {
+    const currentVersion = getVersion(currentTag);
+    const currentSuffix = getSuffix(currentTag);
+    if (!versions.isValidVersion(currentVersion)) {
+      logger.info({ currentFrom }, 'Docker tag is not valid semver - skipping');
+      return upgrades;
+    }
+    let versionList = [];
+    const allTags = await dockerApi.getTags(config.depName, config.logger);
+    if (allTags) {
+      versionList = allTags
+        .filter(tag => getSuffix(tag) === currentSuffix)
+        .map(getVersion)
+        .filter(versions.isValidVersion)
+        .filter(
+          prefix =>
+            prefix.split('.').length === currentVersion.split('.').length
+        )
+        .filter(prefix => compareVersions(prefix, currentVersion) > 0);
+    }
+    logger.debug({ versionList }, 'upgrades versionList');
+    const versionUpgrades = {};
+    for (const version of versionList) {
+      const paddedVersion = padRange(version);
+      const major = semver.major(paddedVersion);
+      if (
+        !versionUpgrades[major] ||
+        compareVersions(version, versionUpgrades[major]) > 0
+      ) {
+        versionUpgrades[major] = version;
+      }
+    }
+    logger.debug({ versionUpgrades }, 'Docker versionUpgrades');
+    const currentMajor = semver.major(padRange(currentVersion));
+    for (const newVersionMajor of Object.keys(versionUpgrades)) {
+      let newTag = versionUpgrades[newVersionMajor];
+      if (currentSuffix) {
+        newTag += `-${currentSuffix}`;
+      }
+      const upgrade = {
+        newTag,
+        newVersionMajor,
+      };
+      upgrade.currentVersion = config.currentTag;
+      upgrade.newVersion = upgrade.newTag;
+      upgrade.newFrom = `${config.depName}:${upgrade.newTag}`;
+      if (newVersionMajor > currentMajor) {
+        upgrade.type = 'major';
+        upgrade.isMajor = true;
+      } else {
+        upgrade.type = 'minor';
+        upgrade.isMinor = true;
+      }
+      if (config.currentDigest || config.pinDigests) {
+        upgrade.newDigest = await dockerApi.getDigest(
+          config.depName,
+          upgrade.newTag,
+          config.logger
+        );
+        upgrade.newFrom += `@${upgrade.newDigest}`;
+      }
+      upgrades.push(upgrade);
+      logger.info(
+        { currentFrom, newFrom: upgrade.newFrom },
+        'Docker tag version upgrade found'
+      );
+    }
+  }
   return upgrades;
 }
+
+function getVersion(tag) {
+  const split = tag.indexOf('-');
+  return split > 0 ? tag.substring(0, split) : tag;
+}
+
+function getSuffix(tag) {
+  const split = tag.indexOf('-');
+  return split > 0 ? tag.slice(split + 1) : '';
+}
+
+function padRange(range) {
+  return range + '.0'.repeat(3 - range.split('.').length);
+}
diff --git a/package.json b/package.json
index e61637f4680a5fd1abd90237f6dfc292810fbd1c..fed3661ea0c243369a0ee991628cf230cbcc4c28 100644
--- a/package.json
+++ b/package.json
@@ -46,6 +46,7 @@
     "changelog": "1.4.0",
     "child-process-promise": "2.2.1",
     "commander": "2.11.0",
+    "compare-versions": "3.1.0",
     "conventional-commits-detector": "0.1.1",
     "convert-hrtime": "2.0.0",
     "deepcopy": "0.6.3",
diff --git a/test/api/docker.spec.js b/test/api/docker.spec.js
index 2ee71546629ddb44e08a205e4e9cc9cae1151e06..5ce48e2dc591e386e93887db8aa0178d81098d45 100644
--- a/test/api/docker.spec.js
+++ b/test/api/docker.spec.js
@@ -36,4 +36,23 @@ describe('api/docker', () => {
       expect(res).toBe('some-digest');
     });
   });
+  describe('getTags', () => {
+    it('returns null if no token', async () => {
+      got.mockReturnValueOnce({ body: {} });
+      const res = await docker.getTags('node', logger);
+      expect(res).toBe(null);
+    });
+    it('returns tags', async () => {
+      const tags = ['a', 'b'];
+      got.mockReturnValueOnce({ body: { token: 'some-token ' } });
+      got.mockReturnValueOnce({ body: { tags } });
+      const res = await docker.getTags('my/node', logger);
+      expect(res).toBe(tags);
+    });
+    it('returns null on error', async () => {
+      got.mockReturnValueOnce({});
+      const res = await docker.getTags('node', logger);
+      expect(res).toBe(null);
+    });
+  });
 });
diff --git a/test/workers/package/__snapshots__/docker.spec.js.snap b/test/workers/package/__snapshots__/docker.spec.js.snap
new file mode 100644
index 0000000000000000000000000000000000000000..6455d888bfda48415056348927bacbbf6d6a8483
--- /dev/null
+++ b/test/workers/package/__snapshots__/docker.spec.js.snap
@@ -0,0 +1,59 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`lib/workers/package/docker renovateDockerImage adds digest 1`] = `
+Array [
+  Object {
+    "isPin": true,
+    "newDigest": "sha256:one",
+    "newFrom": "some-dep:1.0.0-something@sha256:one",
+    "newTag": "1.0.0-something",
+    "newVersion": "sha256:one",
+    "type": "pin",
+  },
+  Object {
+    "currentVersion": "1.0.0-something",
+    "isMinor": true,
+    "newDigest": undefined,
+    "newFrom": "some-dep:1.1.0-something@undefined",
+    "newTag": "1.1.0-something",
+    "newVersion": "1.1.0-something",
+    "newVersionMajor": "1",
+    "type": "minor",
+  },
+]
+`;
+
+exports[`lib/workers/package/docker renovateDockerImage returns major and minor upgrades 1`] = `
+Array [
+  Object {
+    "currentVersion": "1.0.0",
+    "isMinor": true,
+    "newDigest": "sha256:one",
+    "newFrom": "some-dep:1.2.0@sha256:one",
+    "newTag": "1.2.0",
+    "newVersion": "1.2.0",
+    "newVersionMajor": "1",
+    "type": "minor",
+  },
+  Object {
+    "currentVersion": "1.0.0",
+    "isMajor": true,
+    "newDigest": "sha256:two",
+    "newFrom": "some-dep:2.0.0@sha256:two",
+    "newTag": "2.0.0",
+    "newVersion": "2.0.0",
+    "newVersionMajor": "2",
+    "type": "major",
+  },
+  Object {
+    "currentVersion": "1.0.0",
+    "isMajor": true,
+    "newDigest": "sha256:three",
+    "newFrom": "some-dep:3.0.0@sha256:three",
+    "newTag": "3.0.0",
+    "newVersion": "3.0.0",
+    "newVersionMajor": "3",
+    "type": "major",
+  },
+]
+`;
diff --git a/test/workers/package/docker.spec.js b/test/workers/package/docker.spec.js
index 0db380b7ed59f1a09ea5e7b7e71e88759d8d1b46..571aea0072445605ded0317fc59114e56e8f3832 100644
--- a/test/workers/package/docker.spec.js
+++ b/test/workers/package/docker.spec.js
@@ -5,6 +5,7 @@ const logger = require('../../_fixtures/logger');
 
 // jest.mock('../../../lib/api/docker');
 dockerApi.getDigest = jest.fn();
+dockerApi.getTags = jest.fn();
 
 describe('lib/workers/package/docker', () => {
   describe('renovateDockerImage', () => {
@@ -38,5 +39,43 @@ describe('lib/workers/package/docker', () => {
       expect(res).toHaveLength(1);
       expect(res[0].type).toEqual('pin');
     });
+    it('returns empty if current tag is not valid version', async () => {
+      config.currentTag = 'some-text-tag';
+      dockerApi.getDigest.mockReturnValueOnce(config.currentDigest);
+      expect(await docker.renovateDockerImage(config)).toEqual([]);
+    });
+    it('returns major and minor upgrades', async () => {
+      dockerApi.getDigest.mockReturnValueOnce(config.currentDigest);
+      dockerApi.getDigest.mockReturnValueOnce('sha256:one');
+      dockerApi.getDigest.mockReturnValueOnce('sha256:two');
+      dockerApi.getDigest.mockReturnValueOnce('sha256:three');
+      dockerApi.getTags.mockReturnValueOnce([
+        '1.1.0',
+        '1.2.0',
+        '2.0.0',
+        '3.0.0',
+      ]);
+      const res = await docker.renovateDockerImage(config);
+      expect(res).toMatchSnapshot();
+      expect(res).toHaveLength(3);
+      expect(res[0].type).toEqual('minor');
+      expect(res[0].newVersion).toEqual('1.2.0');
+      expect(res[1].type).toEqual('major');
+      expect(res[2].newVersionMajor).toEqual('3');
+    });
+    it('adds digest', async () => {
+      delete config.currentDigest;
+      config.currentTag = '1.0.0-something';
+      dockerApi.getDigest.mockReturnValueOnce('sha256:one');
+      dockerApi.getTags.mockReturnValueOnce([
+        '1.1.0-something',
+        '1.2.0-otherthing',
+      ]);
+      const res = await docker.renovateDockerImage(config);
+      expect(res).toMatchSnapshot();
+      expect(res).toHaveLength(2);
+      expect(res[1].type).toEqual('minor');
+      expect(res[1].newVersion).toEqual('1.1.0-something');
+    });
   });
 });
diff --git a/test/workers/package/index.spec.js b/test/workers/package/index.spec.js
index 8a3b066be08a9d48dd21976238bbebbee6d9c82f..a13ded8982ace053a8b6b06729db54512bc4aebc 100644
--- a/test/workers/package/index.spec.js
+++ b/test/workers/package/index.spec.js
@@ -40,6 +40,7 @@ describe('lib/workers/package/index', () => {
       npm.renovateNpmPackage.mockReturnValueOnce([
         { type: 'pin' },
         { type: 'major' },
+        { type: 'minor', enabled: false },
       ]);
       const res = await pkgWorker.renovatePackage(config);
       expect(res).toHaveLength(1);
diff --git a/yarn.lock b/yarn.lock
index d5f099a835dafbccc20d90516f0ba1ee1eda63ef..545b5a453ad000cf4c926daceb55a0d0aeb251e3 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -918,6 +918,10 @@ compare-func@^1.3.1:
     array-ify "^1.0.0"
     dot-prop "^3.0.0"
 
+compare-versions@3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.1.0.tgz#43310256a5c555aaed4193c04d8f154cf9c6efd5"
+
 concat-map@0.0.1:
   version "0.0.1"
   resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"