May the source be with you, but remember the KISS principle ;-)
Home Switchboard Unix Administration Red Hat TCP/IP Networks Neoliberalism Toxic Managers
(slightly skeptical) Educational society promoting "Back to basics" movement against IT overcomplexity and  bastardization of classic Unix

MySQL Security


See also

Recommeded Links

Setting initial root password

Resetting Root Password

Securing the Initial MySQL Accou



Apache MS Access to mySql conversion PHP integration ACID Installation
(includes MySQL)
Comparison with other databases Resetting root password on MySQL Humor  Etc

Paul DuBois in his artcle Securing Your MySQL Installation mentions that following areas to pay attention:

Another facet of your strategy should be a concern about system security in general. An attacker who gains root login access to a Unix system running a MySQL server can access the data directory no matter what access restrictions you institute.


Top Visited
Past week
Past month


Old News ;-)

[Aug 19, 2004] Securing MySQL By: Mike Peters

Thanks to its speed and stability, MySQL has earned a place on millions of servers worldwide. MySQL has a simple and effective security mechanism, but administrators must perform a few additional tasks to make a default installation truly secure. The measures we'll talk about below will enable you to better secure your database, but be sure to secure the underlying operating system too.


One key to better security is to run MySQL as its own user.

Create such a user and group with the commands:

# groupadd mysql
# useradd -c "MySQL Server" -d /dev/null -g mysql -s /bin/false mysql

Install MySQL in /usr/local/mysql: ./configure --prefix=/usr/local/mysql --with-mysqld-user=mysql --with-unix-socket-path=/tmp/mysql.sock --with-mysqld-ldflags=-all-static
make install
strip /usr/local/mysql/libexec/mysqld
chown -R root /usr/local/mysql
chown -R mysql /usr/local/mysql/var
chgrp -R mysql /usr/local/mysql

The configure option --with-mysqld-user=mysql enables MySQL to run as the mysql user. The --with-mysqld-ldflags=-all-static option makes it easier to chroot MySQL.

Copy the example configuration file from the MySQL source, support-files/my-medium.cnf, to /etc/my.cnf and set the appropriate permissions: chmod 644 /etc/my.cnf.

Once you have MySQL installed, test the installation. Start MySQL with /usr/local/mysql/bin/mysqld_safe & and log on as the root user, mysql -u root. If you see the MySQL prompt you know the database is running you can proceed to chroot it. If the installation is not working, examine the log files to find out what the problem is. Otherwise, shutdown the server: usr/local/mysql/bin/mysqladmin -u root shutdown

Chrooting MySQL

First, create the necessary directory structure for the database:

mkdir -p /chroot/mysql/dev /chroot/mysql/etc /chroot/mysql/tmp /chroot/mysql/var/tmp /chroot/mysql/usr/local/mysql/libexec /chroot/mysql/usr/local/mysql/share/mysql/english

Now set the correct directory permissions:

chown -R root:sys /chroot/mysql
chmod -R 755 /chroot/mysql
chmod 1777 /chroot/mysql/tmp

Once the directories are set up, copy the server's files:

cp /usr/local/mysql/libexec/mysqld /chroot/mysql/usr/local/mysql/libexec/
cp /usr/local/mysql/share/mysql/english/errmsg.sys /chroot/mysql/usr/local/mysql/share/mysql/english/
cp -r /usr/local/mysql/share/mysql/charsets /chroot/mysql/usr/local/mysql/share/mysql/
cp /etc/hosts /chroot/mysql/etc/
cp /etc/host.conf /chroot/mysql/etc/
cp /etc/resolv.conf /chroot/mysql/etc/
cp /etc/group /chroot/mysql/etc/
cp /etc/master.passwd /chroot/mysql/etc/passwords
cp /etc/my.cnf /chroot/mysql/etc/

Finally, copy the mysql databases that contain the grant tables storing the MySQL access privileges:

cp -R /usr/local/mysql/var/ /chroot/mysql/usr/local/mysql/var
chown -R mysql:mysql /chroot/mysql/usr/local/mysql/var

Now create null device:

mknod /chroot/mysql/dev/null c 2 2
chown root:sys /chroot/mysql/dev/null
chmod 666 /chroot/mysql/dev/null

Edit the password and groups files to remove any entries except for the mysql user and group:

mysql:x:12347:12348:MySQL Server:/dev/null:/bin/false


In order for PHP to be able to access MySQL you need to create a link to mysql.sock: ln /chroot/mysql/tmp/mysql.sock /chroot/httpd/tmp/. /chroot/mysql/tmp/mysql.sock and /chroot/httpd/tmp/ need to be on same filesystem. This needs to be done every time you start up the MySQL server. An example startup script below will handle this.

To run MySQL in a chrooted environment as a user other than root, you need to install the chrootuid program. Once you've installed chrootuid, test the server: chrootuid /chroot/mysql mysql /usr/local/mysql/libexec/mysqld &. This will run the server as the mysql user.

The MySQL root user and default accounts

The MySQL root user should not be confused with the system root user. By default, the MySQL root user has no password. You can check this with mysql -u root; if you get a mysql prompt, no root password is set. The first thing you should do is set a strong password for this user. Never give the system root password to the MySQL root user.

To set the initial root password, open a mysql prompt -- mysql -u root mysql -- and enter the following:

mysql> UPDATE user SET Password=PASSWORD('new_password')
    ->             WHERE user='root';

Don't forget to FLUSH PRIVILEGES; to make the privileges effective.

As well as setting the root password, you should remove anonymous accounts:

mysql> DELETE FROM user WHERE User = '';

Alternatively, set a password for the anonymous accounts:

mysql> UPDATE user SET Password = PASSWORD('new_password')
    ->     WHERE User = '';

MySQL privilege system and MySQL users

The MySQL privilege system allows for authentication of users connecting from specific hosts. Authenticated users can be assigned privileges such as SELECT, INSERT, UPDATE, and DELETE on a per database, table, column, or host basis. When a user connects, MySQL first checks if that user is authorized to connect, based on the host and supplied password. If the user is allowed to connect, MySQL then checks each statement to see if the user is allowed to perform the requested action.

When creating new MySQL users, always give the users a strong password, and never store passwords as plain text. Only allow the minimum amount of privileges for a user to accomplish a task, and set those privileges on a per database basis. Some extra time spent planning what privileges to assign to users goes a long way in ensuring the security of your data.

You can create a new user with specific privileges using the GRANT statement. For example:

GRANT USAGE ON myapp.* TO 'someuser'@'localhost' IDENTIFIED BY 'some_pass';

This statement creates a MySQL user named someuser who has access to all tables in the myapp database. The USAGE option sets all of the user's privileges to No, meaning you must enable specific privileges later. You may replace USAGE with a list of specific privileges. IDENTIFIED BY 'some_pass' sets the accounts password to 'some_pass'; GRANT automatically encrypts the password for you. Finally, this user can only connect from localhost. FLUSH PRIVILEGES; makes privilege changes effective.

MySQL access privileges are stored in the grant tables of the mysql database. You should never grant normal users privileges to edit entries in the mysql database. That right should be reserved for the root user. There are several tables in the mysql database that allow for a fine-grained level of control over user privileges.

The user table is the most important of the MySQL grant tables. It contains the usernames and passwords for all users, as well as the hosts from which users can connect. There are are also many fields specifying a wide range of privileges, such as SELECT, INSERT, DELETE, FILE, and PROCESS. You should examine this table and the MySQL manual yourself to become familiar with all the options available. Setting a value of 'N' for a field disables the privilege and 'Y' enables it.

You can change privileges using an SQL UPDATE command or the GRANT statement. If you are using SQL statements such as UPDATE or INSERT to update or set user passwords, be sure to use the PASSWORD() function to encrypt the password in the database. Finally, remember to FLUSH PRIVILEGES; for any changes you make so that they become effective:

UPDATE user SET Host='localhost', Password=PASSWORD('new_pass'), Reload_priv='Y', Process_priv='Y' WHERE

Of the different privileges, most are self-explanatory, but some bear special consideration. PROCESS and SUPER should never be given to untrusted users. A user with these privileges may run mysqladmin processlist, which shows a list of currently executing queries. This list could potentially reveal sensitive data such as passwords.

FILE should also not be granted lightly. This privilege allows users to read and write files anywhere on the filesystem to which the mysqld process has access.

Privileges with system administrative rights or database administrative rights, such as FILE, GRANT, ALTER, SHOW DATABASE, RELOAD, SHUTDOWN, PROCESS, and SUPER, should not generally be given to accounts used by specific applications, especially Web-based applications. Furthermore, accounts for specific applications should have access only to the databases related to that specific application.

The other tables in the mysql database give an even finer-grained level of control over privileges:

db -- controls the access of users to specific databases.

tables_priv -- controls the access of users to specific tables.

columns_priv -- controls the access of users to specific columns of a table.

hosts -- specify the actions which can be performed from a particular host.

One final point is that, if you don't completely trust your DNS, use IP numbers in grant tables in place of host names. This makes it more difficult to spoof hosts.

Local security

In addition to MySQL privileges, there are a number of measures you need to take to improve security on the local machine. Most importantly, never run mysqld as root, as, among other risks, any user with the FILE privilege would then be capable of creating files as the root user.

Make sure that only the mysql user has read and write access to the database directory. Data in the database files can be viewed with any text editor, so any user with read or write access to the files could read or alter data, bypassing MySQL's privileges.

The mysql command history is stored in $HOME/.mysql_history. This file may show sensitive information such as passwords. You should clear the file with echo > $HOME/.mysql_history. To prevent the file being written to in the future, link the .mysql_history files of administrative users to /dev/null: ln -s /dev/null .mysql_history.

If you are using MySQL only on the local machine -- for example for PHP Web-based applications -- then in /chroot/mysql/etc/my.cnf add the line skip-networking to the [mysqld] section. This disables all TCP networking features of the MySQL daemon.

You can also disable the use of the LOAD DATA LOCAL INFILE command, which allows reading of local files and is potentially dangerous. Add the line set-variable=local-infile=0 to the [mysqld] section of /chroot/mysql/etc/my.cnf.

Finally, add the line socket = /chroot/mysql/tmp/mysql.sock to the [client] section of /etc/my.cnf. Notice that we are adding this line to /etc/my.cnf, not /chroot/mysql/etc/my.cnf. This is because, while the MySQL server daemon will use /chroot/mysql/etc/my.cnf, MySQL administrative programs such as mysqladmin are not in the chroot environment and will therefore read configuration from /etc/my.cnf.

Securing remote access

The most important step in securing remote access to your MySQL server is in having a firewall. Your firewall should allow only trusted hosts access to MySQL's port, 3306. Better still is to firewall off your MySQL server altogether and allow access onlythrough a Secure Shell (SSH) tunnel, as described below.

Always use passwords for user accounts, even for trusted client programs. The password in a mysql connection is sent encrypted, but in versions prior to 4.1.1, encryption was not particularly strong. In version 4.1.1 the encryption algorithm was much improved.

Even though the password is sent encrypted, data is sent as plain text. If you are connecting across an untrusted network, you should use an SSH encrypted tunnel. SSH tunneling allows you to connect to a MySQL server from behind a firewall, even when the MySQL port is blocked.

To set up tunnel, use the command ssh ssh_server -L 5001:mysql_server:3306 sleep 99999. You need not have direct access to mysql_server, provided ssh_server does. Now you can connect to port 5001 on the local machine with your favorite database client and the connection will be forwarded silently to the remote machine in an encrypted SSH tunnel.


Be sure to make regular backups of your databases. MySQL includes two utilities which make this easy, mysqlhotcopy and mysqldump.

To use mysqlhotcopy, a user needs access to the files for the tables that he is backing up, the SELECT privilege for those tables, and the RELOAD privilege, in order to execute FLUSH TABLES. You can backup a database using mysqlhotcopy db_name [/path/to/backup_db_dir].

mysqldump supports more options and is especially useful for copying databases between servers, backing up multiple databases at once, or making backups of the database structure only. Databases can be backed up using one of the following commands:

mysqldump [options] db_name [tables]
mysqldump [options] --databases DB1 [DB2 DB3...]
mysqldump [options] --all-databases

For example, you can back-up all your databases and compress them in one go with the command:
date=`date -I`; mysqldump --opt --all-databases -u user --password="your_pass" | bzip2 -c > databasebackup-$date.sql.bz2

The --opt option is shorthand for --add-drop-table --add-locks --create-options --disable-keys --extended-insert --lock-tables --quick --set-charset. This should create a backup which is quick and easy to restore. In fact this option is enabled by default in versions 4.1 and later; you can disable it with --skip-opt.

To restore a database from a file created by mysqldump you just need to run mysql -u user -p db_name < backup-file.sql. The -p option tells mysql to prompt for a password.

Server startup

The following script can be used to start your MySQL server:



echo -n " mysql"

case "$1" in
        rm -rf ${CHROOT_PHP}/${SOCKET}
        nohup ${CHROOTUID} ${CHROOT_MYSQL} mysql ${MYSQLD} >/dev/null 2>&1 &
        sleep 5 && ln ${CHROOT_MYSQL}/${SOCKET} ${CHROOT_PHP}/${SOCKET}
        kill `cat ${CHROOT_MYSQL}/${PIDFILE}`
        rm -rf ${CHROOT_MYSQL}/${SOCKET}
        echo ""
        echo "Usage: `basename $0` {start|stop}" >&2
        exit 64

exit 0


Using these procedures will reduce the risk of a potential breakin to your database server. MySQL's extensive privilege system allows you to protect the data stored within the database. As always you should remain vigilant, and be sure to apply patches and upgrades to your server as they become available.

Mike Peters is a freelance consultant and programmer and long-time Linux user.


Litchfield had already been researching weaknesses in Oracle 9iAS when Ellison boasted of Oracle security. Litchfield, of NGS Software Ltd (, had been working on a commercial scanning tool that would audit Oracle servers for flaws in application logic. Litchfield had focused on five of the front end application environments used to access Oracle 9iAS from Web servers, and found buffer overflows, denial of service, ability to read scripts, remote administration of the server, and execution of arbitrary commands.

Of course, this news will be old when you read this, and if you use Oracle 9iAS, you will surely have installed the patches of workarounds for all of these issues. But I consider it worthwhile for network security people, who aren't database admins, to better understand the issues raised by Litchfield.

Figure 1 shows how the various components of Web server using a backend database server are arranged. Firewalls protect both the Web server and the internal network, only permitting limited access between the Web server and the internal network. In the case of MS SQL, the problem is easier, as SQL Server listens at a single, known port (1433/tcp by default, although this port number can be changed through configuration). Oracle servers use a more complex system, where a TNS (Transparent Network Substrate) Listener listens at port 1521/TCP, and arranges for connections to the actual server. For firewalls, this means that a simple packet filtering rule will not work, but an application gateway or stateful packet filter rule that understands the TNS Listener protocol must open connections for access to the Oracle server.

The front end software, that runs on the Web server itself, can be written in many different programming languages. Litchfield reported the most problems in PL/SQL (Procedural Language/ Structured Query Language). PL/SQL had buffer overflow issues, directory traversal issues, remote administration of DADs (Database Access Descriptors), and the ability to display source code and database schema information. Litchfiled also demonstrated a technique to bypass authentication, through the use of utility procedures included in a default install of Oracle 9iAS (the OWA_UTIL package).

The Oracle Java Servlet programming interface permitted reading the source code for the Java servlets themselves. The Java source code files are created on the fly in directories that should be protected, so that remote users cannot access them. Oracle uses the Apache Web server, even when used on Windows 2000 systems, so you need to follow instructions for configuring Apache to prevent access to the directories containing these files.

Usernames and passwords are exposed if remote users are permitted to read scripts or source code. A connection to the SQL server requires a valid username and password combination, and this combination can be found in a software used on Web servers-- if it can be read. The same information can also be found in configuration files on the Oracle server, and Litchfield also provided tricks for viewing this data as well.

To make matters worse, Litchfield reported that it is not uncommon for programmers and database administrators to leave default passwords unchanged. Litchfield listed 160 default username and password combinations.

The TNS Listener had vulnerabilities of its own. If an attacker can connect to the Listener, the attacker could potentially load any library on the system where the attacker is located, and execute functions found in that library. Both UNIX and Windows 2000 libraries include the system() function, that can execute programs with the privileges of the Listener process. The TNS Listener will normally be protected by firewall rules from connections by external attackers, except one coming from the Web server itself.

While this litany of exploits makes Oracle security sound pretty poor, Oracle has worked at building secure software, and has a history of hiring external auditors to examine its code, and has sought (and actually acchieved) some trusted system evaluations. And all of these attacks have corresponding patches or workarounds that can be found at the Oracle patch site (see Resources).


SQL injection, or SQL poisoning, should actually be familiar to anyone who has read my articles about securing Web servers. SQL injection is an attack very similar to those that are used against CGI (Common Gateway Interface) programs or scripts. In SQL injection, the attacker includes something in a response from a Web browser that the script writer didn't anticipate. The main difference between SQL injection and other CGI attacks is that the attack relies on some basic understanding of SQL.

Structured Query Language was originally an invention of IBM, and is now an ANSI standard. With SQL,
someone who is not a programmer can make requests to a database server and perhaps even get back the information requested. Of course, SQL is really not that simple, and it is possible for a naive SQL user to make very resource intensive SQL queries, or, more likely, get nothing back but incomprehensible error messages.

For our purposes, all you really need to know about is a very basic database query request, SELECT. The basic syntax for a SELECT request is "SELECT _select-list_ From _table-name_ Where _condition_". This roughly translates to: "Select the data matching the select-list from table-name that matches this condition." In an ASP script, the SELECT string might be built first, so it can be passed later to a Microsoft SQL Server using a line like:

WHERE ID = " & Request.QueryString("CAT") </pre>

The call Request.QueryString("CAT") extracts the value of the Web form variable "CAT" so it can be appended as the SELECT condition, for example "CAT = blenders". Now, SQL server can return all rows matching the category "blenders".

But, there is a problem with this script fragment. The value of the "CAT" variable is blindly accepted. What if the wiley attacker had sent "blenders+OR+1=1"? Now, the condition will always be true, and all rows will be returned. If the database table named PRODUCTS contains nothing that must remain confidential, that really isn't much of a problem. But, suppose the request was for customer account information, or something else that should be kept private?

SQL Server treats the non-printing character one, represented in URL encoding as %01, as a line delimiter. When the Web server script does not check the value provided by the remote "user", the value could be "blenders%01DROP+TABLE+PRODUCTS". Dropping a table means to delete it from the database, and is probably not something you want.

The most interesting attack comes through the use of stored procedures. Stored procedures are SQL subroutines, some of which come bundled with your SQL server. For Microsoft's SQL Server, the extended stored procedure xp_cmdshell executes programs in the context of the SQL Server, which you (hopefully) have configured as some special account with few privileges (like Guest group, and Login as a Service privilege). Software Development Kits (SDK), like the ones that come with .NET, use the default account, sa, a member of the Administrators group, and while this is convenient for a programmer, it is a disaster for security.

Again, using the same SELECT example, the attacker sets the value of "CAT" to be "blenders%01EXEC+master..xp_cmdshell+ net+user+crack+secret+/ADD". If SQL Server is running as the sa user, you now have a new user account named "crack" with a password of "secret". A second SELECT statement could be used to add the "crack" user to the Administrators group.

SQL Server has other, interesting extended stored procedures, for registry access and database administration (adding users, changing passwords, etc.). If you are running MS-SQL Server, it is also possible to access MS-SQL Server, and these procedures, using pipes connecting to port 139/TCP.

By now, I am hoping that you have gotten the point. Your front end software, whether it be PL/SQL or ASP, cannot blindly accept input from remote users. You must filter the input so that it will resemble what you expect. If it is a number, check to see that the value contains only digits and dots. If it is a name, check to see that the value contains letters (and dots and dashes) that can occur in a person's name. And so on.

If this seems painfully obvious, a company running the Microsoft Developers Store Web site, under contract to Microsoft, had this very problem in January 2002 (see Resources). And they are not the only site, by any means.

One organization, the Open Web Application Security Project, is working on developing a set of filters that will block evil characters (like %01), and make it easy to configure filters that will only permit the answers you expect in a value. Of course, you can do a lot of this today, just by carefully checking the value of any variable you will be reading from the remote Web browser.


Adding a database backend to your Web server adds lots of functionality, and lots of potential security holes. The usual rules for securing servers apply to backend database servers as well. That is, secure the server, and run the database process with the lowest privileges possible.

Securing servers is something I have often written about. What has changed over time is that the position of Microsoft servers has shifted when compared to Linux systems. Windows 2000 Professional Server comes, with a default installation, with dozens of network services, while new Linux distributions come with most everything disabled.

The user account that runs the database server should be a nonprivileged user. You might encounter several problems here, as Oracle wants to run as LocalSystem, and many software packages that come with a bundled MS-SQL Server will use the default sa account.

The usual admonitions to install security patches as soon as possible apply to databases as well. Both Oracle 9iAS and MS-SQL (both 7 and 2000 versions) have numerous security patches that must be applied, and this will be true for other SQL servers as well.

Just because you don't understand SQL servers doesn't mean that attackers don't either. All it takes is for one person to write an exploit, and your site is toast. Secure your servers.

MySQL MySQL 5.0 Reference Manual 5.3.2 Making MySQL Secure Against Attackers

David Tonhofer

On Unix, if the MySQL server has been compiled with TCP wrappers (--with-libwrap=DIR), (the default with the pre-compiled binaries?), then you can additionally control access to MySQL's TCP port in a very fine-grained manner, even before the MySQL access control system kicks in.

See the man page:

"man tcpd"

and the description of the format of "/etc/hosts.allow" and "/etc/hosts.deny":

"man 5 hosts_access"

Recommended Links

Securing Your MySQL Installation by Paul DuBois 2003-01-25

MS SQL FAQ and search tool sqlping:

Input filters for Web server applications:

Microsoft Developer's store vulnerable to SQL poisoning:

Presentations and recordings of past BlackHat conference presentations (look for David Litchfield, JD Glaser, Chip Andrews and others):

David Litchfield's site, with software and presentations:

Oracle site for downloading patches:



Groupthink : Two Party System as Polyarchy : Corruption of Regulators : Bureaucracies : Understanding Micromanagers and Control Freaks : Toxic Managers :   Harvard Mafia : Diplomatic Communication : Surviving a Bad Performance Review : Insufficient Retirement Funds as Immanent Problem of Neoliberal Regime : PseudoScience : Who Rules America : Neoliberalism  : The Iron Law of Oligarchy : Libertarian Philosophy


War and Peace : Skeptical Finance : John Kenneth Galbraith :Talleyrand : Oscar Wilde : Otto Von Bismarck : Keynes : George Carlin : Skeptics : Propaganda  : SE quotes : Language Design and Programming Quotes : Random IT-related quotesSomerset Maugham : Marcus Aurelius : Kurt Vonnegut : Eric Hoffer : Winston Churchill : Napoleon Bonaparte : Ambrose BierceBernard Shaw : Mark Twain Quotes


Vol 25, No.12 (December, 2013) Rational Fools vs. Efficient Crooks The efficient markets hypothesis : Political Skeptic Bulletin, 2013 : Unemployment Bulletin, 2010 :  Vol 23, No.10 (October, 2011) An observation about corporate security departments : Slightly Skeptical Euromaydan Chronicles, June 2014 : Greenspan legacy bulletin, 2008 : Vol 25, No.10 (October, 2013) Cryptolocker Trojan (Win32/Crilock.A) : Vol 25, No.08 (August, 2013) Cloud providers as intelligence collection hubs : Financial Humor Bulletin, 2010 : Inequality Bulletin, 2009 : Financial Humor Bulletin, 2008 : Copyleft Problems Bulletin, 2004 : Financial Humor Bulletin, 2011 : Energy Bulletin, 2010 : Malware Protection Bulletin, 2010 : Vol 26, No.1 (January, 2013) Object-Oriented Cult : Political Skeptic Bulletin, 2011 : Vol 23, No.11 (November, 2011) Softpanorama classification of sysadmin horror stories : Vol 25, No.05 (May, 2013) Corporate bullshit as a communication method  : Vol 25, No.06 (June, 2013) A Note on the Relationship of Brooks Law and Conway Law


Fifty glorious years (1950-2000): the triumph of the US computer engineering : Donald Knuth : TAoCP and its Influence of Computer Science : Richard Stallman : Linus Torvalds  : Larry Wall  : John K. Ousterhout : CTSS : Multix OS Unix History : Unix shell history : VI editor : History of pipes concept : Solaris : MS DOSProgramming Languages History : PL/1 : Simula 67 : C : History of GCC developmentScripting Languages : Perl history   : OS History : Mail : DNS : SSH : CPU Instruction Sets : SPARC systems 1987-2006 : Norton Commander : Norton Utilities : Norton Ghost : Frontpage history : Malware Defense History : GNU Screen : OSS early history

Classic books:

The Peter Principle : Parkinson Law : 1984 : The Mythical Man-MonthHow to Solve It by George Polya : The Art of Computer Programming : The Elements of Programming Style : The Unix Haterís Handbook : The Jargon file : The True Believer : Programming Pearls : The Good Soldier Svejk : The Power Elite

Most popular humor pages:

Manifest of the Softpanorama IT Slacker Society : Ten Commandments of the IT Slackers Society : Computer Humor Collection : BSD Logo Story : The Cuckoo's Egg : IT Slang : C++ Humor : ARE YOU A BBS ADDICT? : The Perl Purity Test : Object oriented programmers of all nations : Financial Humor : Financial Humor Bulletin, 2008 : Financial Humor Bulletin, 2010 : The Most Comprehensive Collection of Editor-related Humor : Programming Language Humor : Goldman Sachs related humor : Greenspan humor : C Humor : Scripting Humor : Real Programmers Humor : Web Humor : GPL-related Humor : OFM Humor : Politically Incorrect Humor : IDS Humor : "Linux Sucks" Humor : Russian Musical Humor : Best Russian Programmer Humor : Microsoft plans to buy Catholic Church : Richard Stallman Related Humor : Admin Humor : Perl-related Humor : Linus Torvalds Related humor : PseudoScience Related Humor : Networking Humor : Shell Humor : Financial Humor Bulletin, 2011 : Financial Humor Bulletin, 2012 : Financial Humor Bulletin, 2013 : Java Humor : Software Engineering Humor : Sun Solaris Related Humor : Education Humor : IBM Humor : Assembler-related Humor : VIM Humor : Computer Viruses Humor : Bright tomorrow is rescheduled to a day after tomorrow : Classic Computer Humor

The Last but not Least Technology is dominated by two types of people: those who understand what they do not manage and those who manage what they do not understand ~Archibald Putt. Ph.D

Copyright © 1996-2021 by Softpanorama Society. was initially created as a service to the (now defunct) UN Sustainable Development Networking Programme (SDNP) without any remuneration. This document is an industrial compilation designed and created exclusively for educational use and is distributed under the Softpanorama Content License. Original materials copyright belong to respective owners. Quotes are made for educational purposes only in compliance with the fair use doctrine.

FAIR USE NOTICE This site contains copyrighted material the use of which has not always been specifically authorized by the copyright owner. We are making such material available to advance understanding of computer science, IT technology, economic, scientific, and social issues. We believe this constitutes a 'fair use' of any such copyrighted material as provided by section 107 of the US Copyright Law according to which such material can be distributed without profit exclusively for research and educational purposes.

This is a Spartan WHYFF (We Help You For Free) site written by people for whom English is not a native language. Grammar and spelling errors should be expected. The site contain some broken links as it develops like a living tree...

You can use PayPal to to buy a cup of coffee for authors of this site


The statements, views and opinions presented on this web page are those of the author (or referenced source) and are not endorsed by, nor do they necessarily reflect, the opinions of the Softpanorama society. We do not warrant the correctness of the information provided or its fitness for any purpose. The site uses AdSense so you need to be aware of Google privacy policy. You you do not want to be tracked by Google please disable Javascript for this site. This site is perfectly usable without Javascript.

Last modified: March 12, 2019