diff --git a/man/man8/xfs_quota.8 b/man/man8/xfs_quota.8
index e6fe7cd1..dd0479cd 100644
--- a/man/man8/xfs_quota.8
+++ b/man/man8/xfs_quota.8
@@ -457,14 +457,46 @@ must be specified.
 .B \-bir
 ]
 .I value
+[
+.B -d
+|
+.I id
+|
+.I name
+]
 .br
 Allows the quota enforcement timeout (i.e. the amount of time allowed
 to pass before the soft limits are enforced as the hard limits) to
 be modified. The current timeout setting can be displayed using the
 .B state
-command. The value argument is a number of seconds, but units of
-\&'minutes', 'hours', 'days', and 'weeks' are also understood
+command.
+.br
+When setting the default timer via the
+.B \-d
+option, or for
+.B id
+0, or if no argument is given after
+.I value
+the
+.I value
+argument is a number of seconds indicating the relative amount of time after
+soft limits are exceeded, before hard limits are enforced.
+.br
+When setting any other individual timer by
+.I id
+or
+.I name,
+the
+.I value
+is the number of seconds from now, at which time the hard limits will be enforced.
+This allows extending the grace time of an individual user who has exceeded soft
+limits.
+.br
+For
+.I value,
+units of \&'minutes', 'hours', 'days', and 'weeks' are also understood
 (as are their abbreviations 'm', 'h', 'd', and 'w').
+.br
 .HP
 .B warn
 [
diff --git a/quota/edit.c b/quota/edit.c
index 442b608c..b60d0b13 100644
--- a/quota/edit.c
+++ b/quota/edit.c
@@ -419,6 +419,7 @@ restore_f(
 
 static void
 set_timer(
+	uint32_t	id,
 	uint		type,
 	uint		mask,
 	char		*dev,
@@ -427,14 +428,41 @@ set_timer(
 	fs_disk_quota_t	d;
 
 	memset(&d, 0, sizeof(d));
+
+	/*
+	 * If id is specified we are extending grace time by value
+	 * Otherwise we are setting the default grace time
+	 */
+	if (id) {
+		time_t	now;
+
+		if (xfsquotactl(XFS_GETQUOTA, dev, type, id, (void *)&d) < 0) {
+			exitcode = 1;
+			fprintf(stderr, _("%s: cannot get quota: %s\n"),
+					progname, strerror(errno));
+				return;
+		}
+
+		time(&now);
+
+		if (d.d_blk_hardlimit && d.d_bcount > d.d_blk_hardlimit)
+			d.d_btimer = now + value;
+		if (d.d_ino_softlimit && d.d_icount > d.d_ino_softlimit)
+			d.d_itimer = now + value;
+		if (d.d_rtb_softlimit && d.d_rtbcount > d.d_rtb_softlimit)
+			d.d_rtbtimer = now + value;
+	} else {
+		d.d_btimer = value;
+		d.d_itimer = value;
+		d.d_rtbtimer = value;
+	}
+
 	d.d_version = FS_DQUOT_VERSION;
 	d.d_flags = type;
 	d.d_fieldmask = mask;
-	d.d_itimer = value;
-	d.d_btimer = value;
-	d.d_rtbtimer = value;
+	d.d_id = id;
 
-	if (xfsquotactl(XFS_SETQLIM, dev, type, 0, (void *)&d) < 0) {
+	if (xfsquotactl(XFS_SETQLIM, dev, type, id, (void *)&d) < 0) {
 		exitcode = 1;
 		fprintf(stderr, _("%s: cannot set timer: %s\n"),
 				progname, strerror(errno));
@@ -447,10 +475,15 @@ timer_f(
 	char		**argv)
 {
 	uint		value;
-	int		c, type = 0, mask = 0;
+	char		*name = NULL;
+	uint32_t	id = 0;
+	int		c, type = 0, mask = 0, flags = 0;
 
-	while ((c = getopt(argc, argv, "bgipru")) != EOF) {
+	while ((c = getopt(argc, argv, "bdgipru")) != EOF) {
 		switch (c) {
+		case 'd':
+			flags |= DEFAULTS_FLAG;
+			break;
 		case 'b':
 			mask |= FS_DQ_BTIMER;
 			break;
@@ -474,23 +507,45 @@ timer_f(
 		}
 	}
 
-	if (argc != optind + 1)
+	 /*
+	 * Older versions of the command did not accept -d|id|name,
+	 * so in that case we assume we're setting default timer,
+	 * and the last arg is the timer value.
+	 *
+	 * Otherwise, if the defaults flag is set, we expect 1 more arg for
+	 * timer value ; if not, 2 more args: 1 for value, one for id/name.
+	 */
+	if (!(flags & DEFAULTS_FLAG) && (argc == optind + 1)) {
+		value = cvttime(argv[optind++]);
+	} else if (flags & DEFAULTS_FLAG) {
+		if (argc != optind + 1)
+			return command_usage(&timer_cmd);
+		value = cvttime(argv[optind++]);
+	} else if (argc == optind + 2) {
+		value = cvttime(argv[optind++]);
+		name = (flags & DEFAULTS_FLAG) ? "0" : argv[optind++];
+	} else
 		return command_usage(&timer_cmd);
 
-	value = cvttime(argv[optind++]);
 
+	/* if none of -bir specified, set them all */
 	if (!mask)
 		mask = FS_DQ_TIMER_MASK;
 
 	if (!type) {
 		type = XFS_USER_QUOTA;
 	} else if (type != XFS_GROUP_QUOTA &&
-	           type != XFS_PROJ_QUOTA &&
-	           type != XFS_USER_QUOTA) {
+		   type != XFS_PROJ_QUOTA &&
+		   type != XFS_USER_QUOTA) {
 		return command_usage(&timer_cmd);
 	}
 
-	set_timer(type, mask, fs_path->fs_name, value);
+	if (name)
+		id = id_from_string(name, type);
+
+	if (id >= 0)
+		set_timer(id, type, mask, fs_path->fs_name, value);
+
 	return 0;
 }
 
@@ -616,9 +671,9 @@ edit_init(void)
 
 	timer_cmd.name = "timer";
 	timer_cmd.cfunc = timer_f;
-	timer_cmd.argmin = 2;
+	timer_cmd.argmin = 1;
 	timer_cmd.argmax = -1;
-	timer_cmd.args = _("[-bir] [-g|-p|-u] value");
+	timer_cmd.args = _("[-bir] [-g|-p|-u] value [-d|id|name]");
 	timer_cmd.oneline = _("set quota enforcement timeouts");
 	timer_cmd.help = timer_help;
 	timer_cmd.flags = CMD_FLAG_FOREIGN_OK;
