diff --git a/dwm.c b/dwm.c
index 71bd8b9..97485d6 100644
--- a/dwm.c
+++ b/dwm.c
@@ -199,6 +199,7 @@ static Client *nexttiled(Client *c);
 static void pop(Client *c);
 static void propertynotify(XEvent *e);
 static void quit(const Arg *arg);
+static void restoresession(void);
 static Monitor *recttomon(int x, int y, int w, int h);
 static void resize(Client *c, int x, int y, int w, int h, int interact);
 static void resizeclient(Client *c, int x, int y, int w, int h);
@@ -278,6 +279,7 @@ static void (*handler[LASTEvent]) (XEvent *) = {
 	[UnmapNotify] = unmapnotify
 };
 static Atom wmatom[WMLast], netatom[NetLast];
+static Atom dwmatom_tags, dwmatom_mon, dwmatom_index;
 static int running = 1;
 static Cur *cursor[CurLast];
 static Clr **scheme;
@@ -1275,6 +1277,35 @@ manage(Window w, XWindowAttributes *wa)
 		applyrules(c);
 	}
 
+	/* restore tags and monitor from previous dwm session */
+	{
+		Atom da;
+		int di;
+		unsigned long nitems, dl;
+		unsigned char *p = NULL;
+
+		if (XGetWindowProperty(dpy, w, dwmatom_tags, 0L, 1L, True, XA_CARDINAL,
+				&da, &di, &nitems, &dl, &p) == Success && p) {
+			if (nitems == 1)
+				c->tags = (unsigned int)(*(long *)p);
+			XFree(p);
+		}
+		p = NULL;
+		if (XGetWindowProperty(dpy, w, dwmatom_mon, 0L, 1L, True, XA_CARDINAL,
+				&da, &di, &nitems, &dl, &p) == Success && p) {
+			if (nitems == 1) {
+				Monitor *m;
+				int mon = (int)(*(long *)p);
+				for (m = mons; m; m = m->next)
+					if (m->num == mon) {
+						c->mon = m;
+						break;
+					}
+			}
+			XFree(p);
+		}
+	}
+
 	if (c->x + WIDTH(c) > c->mon->wx + c->mon->ww)
 		c->x = c->mon->wx + c->mon->ww - WIDTH(c);
 	if (c->y + HEIGHT(c) > c->mon->wy + c->mon->wh)
@@ -1483,9 +1514,121 @@ propertynotify(XEvent *e)
 	}
 }
 
+void
+restoresession(void)
+{
+	Monitor *m;
+	Client *c, **list;
+	int *indices;
+	int i, n, di;
+	Atom da;
+	unsigned long nitems, dl;
+	unsigned char *p = NULL;
+
+	/* restore client order per monitor */
+	for (m = mons; m; m = m->next) {
+		/* count clients */
+		for (n = 0, c = m->clients; c; c = c->next, n++);
+		if (n == 0)
+			continue;
+
+		list = ecalloc(n, sizeof(Client *));
+		indices = ecalloc(n, sizeof(int));
+		for (i = 0, c = m->clients; c; c = c->next, i++)
+			list[i] = c;
+
+		/* read saved index for each client */
+		for (i = 0; i < n; i++) {
+			p = NULL;
+			indices[i] = n; /* default: high value = end of list */
+			if (XGetWindowProperty(dpy, list[i]->win, dwmatom_index, 0L, 1L, True, XA_CARDINAL,
+					&da, &di, &nitems, &dl, &p) == Success && p) {
+				if (nitems == 1)
+					indices[i] = (int)(*(long *)p);
+				XFree(p);
+			}
+		}
+
+		/* simple insertion sort by saved index */
+		for (i = 1; i < n; i++) {
+			Client *tmp = list[i];
+			int tmpidx = indices[i];
+			int j = i - 1;
+			while (j >= 0 && indices[j] > tmpidx) {
+				list[j + 1] = list[j];
+				indices[j + 1] = indices[j];
+				j--;
+			}
+			list[j + 1] = tmp;
+			indices[j + 1] = tmpidx;
+		}
+
+		/* rebuild the client list */
+		m->clients = list[0];
+		for (i = 0; i < n - 1; i++)
+			list[i]->next = list[i + 1];
+		list[n - 1]->next = NULL;
+
+		free(indices);
+		free(list);
+	}
+
+	/* restore active tagset per monitor */
+	for (m = mons; m; m = m->next) {
+		char atom_name[32];
+		Atom a;
+
+		snprintf(atom_name, sizeof(atom_name), "_DWM_TAGSET_%d", m->num);
+		a = XInternAtom(dpy, atom_name, False);
+		p = NULL;
+		if (XGetWindowProperty(dpy, root, a, 0L, 1L, True, XA_CARDINAL,
+				&da, &di, &nitems, &dl, &p) == Success && p) {
+			if (nitems == 1)
+				m->tagset[m->seltags] = (unsigned int)(*(long *)p);
+			XFree(p);
+		}
+	}
+
+	/* rearrange all monitors */
+	for (m = mons; m; m = m->next)
+		arrange(m);
+
+	focus(NULL);
+	drawbars();
+}
+
 void
 quit(const Arg *arg)
 {
+	Monitor *m;
+	Client *c;
+	int i;
+
+	for (m = mons; m; m = m->next) {
+		i = 0;
+		for (c = m->clients; c; c = c->next, i++) {
+			long tags = (long)c->tags;
+			long mon = (long)m->num;
+			long idx = (long)i;
+			XChangeProperty(dpy, c->win, dwmatom_tags, XA_CARDINAL, 32,
+				PropModeReplace, (unsigned char *)&tags, 1);
+			XChangeProperty(dpy, c->win, dwmatom_mon, XA_CARDINAL, 32,
+				PropModeReplace, (unsigned char *)&mon, 1);
+			XChangeProperty(dpy, c->win, dwmatom_index, XA_CARDINAL, 32,
+				PropModeReplace, (unsigned char *)&idx, 1);
+		}
+		/* save active tagset per monitor on root window */
+		{
+			char atom_name[32];
+			Atom a;
+			long tagset = (long)m->tagset[m->seltags];
+			snprintf(atom_name, sizeof(atom_name), "_DWM_TAGSET_%d", m->num);
+			a = XInternAtom(dpy, atom_name, False);
+			XChangeProperty(dpy, root, a, XA_CARDINAL, 32,
+				PropModeReplace, (unsigned char *)&tagset, 1);
+		}
+	}
+	XSync(dpy, False);
 	running = 0;
 }
 
@@ -1851,6 +1994,9 @@ setup(void)
 	netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
 	netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
 	netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False);
+	dwmatom_tags = XInternAtom(dpy, "_DWM_TAGS", False);
+	dwmatom_mon = XInternAtom(dpy, "_DWM_MON", False);
+	dwmatom_index = XInternAtom(dpy, "_DWM_INDEX", False);
 	/* init cursors */
 	cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr);
 	cursor[CurResize] = drw_cur_create(drw, XC_sizing);
@@ -2531,6 +2677,7 @@ main(int argc, char *argv[])
 		die("pledge");
 #endif /* __OpenBSD__ */
 	scan();
+	restoresession();
 	run();
 	cleanup();
 	XCloseDisplay(dpy);
